Eigene Messklassen entwickeln

Eine Messklasse beschreibt den fachlichen Ablauf einer Messung. Sie koordiniert MGraph, Geräte, Messpunkte, Autosave und Auswertung, enthält aber keine gerätespezifischen SCPI-Befehle und keine Qt-Widgets.

Von Measure erben

from mpylab.env.Measure import Measure

class ExampleMeasurement(Measure):
    def __init__(self, SearchPaths=None):
        super().__init__(SearchPaths=SearchPaths)
        self.raw_data = {}
        self.processed_data = {}

Measure stellt Logging, Bedienerinteraktion, Autosave, Geräteinitialisierung, RF-Off und Pickle-Wiederherstellung bereit. Neue Klassen sollten diese Infrastruktur verwenden, statt eigene Varianten davon einzuführen.

Messablauf

Ein robuster Ablauf hat folgende Form:

  1. Datensatz und Wiederanlaufinformation vorbereiten.

  2. MGraph mit Namen- und Condition-Mapping erzeugen.

  3. Geräte erstellen und über _init_measurement_devices initialisieren.

  4. Den logischen Graph-Context vor jedem frequenzabhängigen Zugriff explizit anwenden. Für Graphen ohne physischen Controller genügt weiterhin die ausdrückliche Condition-Auswertung.

  5. Nur vollständig gemessene Punkte in die Ergebnisstruktur übernehmen.

  6. Regelmäßig do_autosave aufrufen.

  7. In einem finally-Pfad RF abschalten und Geräte beenden.

Die gemeinsame Finalisierung erfolgt über _finalize_measurement_devices. Fehler beim Messen dürfen diesen Sicherheitspfad nicht überspringen.

Expliziten Graph-Context anwenden

Eigene Messanwendungen sollten Frequenz, Betriebsart und vergleichbare fachliche Größen gemeinsam an MGraph.ApplyContext übergeben. Dadurch bleiben Condition-Auswertung, Frequenzeinstellung, physische Umschaltung und Rücklesekontrolle eine zusammenhängende Operation:

from mpylab.tools.mgraph import (
    GraphStateMismatchError,
    MGraph,
    TEM_CONDITION_MAP,
)

graph = MGraph(
    dotfile,
    themap=names,
    SearchPaths=search_paths,
    condition_map=TEM_CONDITION_MAP,
    allow_legacy_condition_context=False,
)
graph.CreateDevices()
graph.Init_Devices()

requested_context = {"frequency": frequency, "mode": "GTEM"}
try:
    context_result = graph.ApplyContext(requested_context)
except GraphStateMismatchError as error:
    # MGraph hat RF bereits abgeschaltet. Die Anwendung protokolliert
    # error.mismatches und fragt den Bediener nach einer Entscheidung.
    if not operator_explicitly_selected_reapply(error.mismatches):
        raise
    graph.ReapplyContext()
    context_result = graph.ApplyContext(requested_context)

GraphStateMismatchError.mismatches enthält je Controller den erwarteten und den gelesenen Zustand sowie gegebenenfalls Status- oder Abfragefehler. Die Anwendung soll diese Information protokollieren und in ihrer CLI oder Oberfläche neutral anzeigen. Sie darf keinen gerätespezifischen Relaiszustand interpretieren; diese Fachkenntnis bleibt im Controller-Treiber.

Bei einer Abweichung hat MGraph bereits graphweit RFOff ausgeführt. Abbrechen ist deshalb die sichere Standardentscheidung. Nur eine ausdrückliche Bedienerwahl darf zuerst mit ReapplyContext den zuletzt geplanten Zustand wiederherstellen. Anschließend wird der ursprünglich angeforderte Context erneut angewendet. Ein bloßes Wiederholen von ApplyContext ist absichtlich nicht ausreichend, weil die externe Schaltaktion sonst unbemerkt überschrieben werden könnte.

CheckContextState erzwingt eine sofortige Kontrolle; PollContextState begrenzt wiederholte Abfragen zeitlich. RFOn_Devices prüft immer unmittelbar vor dem Einschalten. Read und NBRead binden eine zeitlich begrenzte Kontrolle in Messschleifen ein. Das ersetzt keinen asynchronen Hardware-Watchdog, erkennt externe Eingriffe aber an den relevanten Programmgrenzen.

Die erforderlichen DOT-Attribute und der Treibervertrag sind in der DOT-Referenz beschrieben. Die kuratierte MGraph-API enthält Rückgabewert und Exceptions.

Autosave- und Resume-Schema

Vor dem ersten Autosave setzt die Routine eine strukturierte Wiederanlaufinformation:

self.set_autosave_resume(
    measurement="example",
    method="Measure_Example",
    description=description,
)

Die Messroutine muss vorhandene Daten beim Wiederanlauf erkennen und am ersten unvollständigen Punkt fortsetzen. Der zugehörige Test prüft daher Aufrufzahlen und Ergebnisdaten, nicht nur die Lesbarkeit des Pickles.

Datenstruktur

Frequenzabhängige Daten werden bevorzugt als dataset[frequency] = quantity oder in einer klar dokumentierten, gleichwertigen Struktur abgelegt. Rohdaten, Auswertedaten und Metadaten bleiben getrennt. Referenzen auf vorbereitende Messungen werden mit Datensatzschlüssel und Quelle gespeichert, damit Reports die Rückführbarkeit ohne Neuberechnung darstellen können.

Auswertung

Messung und Auswertung sind getrennte Methoden. Dadurch lassen sich Auswertealgorithmen erneut auf ein after-measure-Pickle anwenden, ohne Hardware anzusprechen. Eine Auswertung verändert keine Rohdaten und dokumentiert verwendete Referenzdatensätze sowie relevante Parameter.