Durchgängiges Entwicklertutorial ================================ Dieses Tutorial zeigt den empfohlenen Weg zu einer eigenen mpylab-Anwendung. Es beginnt bewusst mit einer vorhandenen Messklasse und virtuellen Geräten. Eine neue Messklasse oder ein neuer Treiber wird erst dann ergänzt, wenn die vorhandenen Erweiterungspunkte nicht ausreichen. Das Beispiel verwendet den direkten Verstärkertest. Die vollständige Referenzkonfiguration liegt unter ``script/conf/amplifier-test-direct-virtual``. 1. Messaufgabe abgrenzen ------------------------ Vor dem ersten Code sollten vier Fragen beantwortet sein: * Welche Messklasse beschreibt den fachlichen Ablauf am besten? * Welche Geräte und korrigierten Signalpfade benötigt sie? * Welche Größen werden als SCUQ-Quantities gespeichert? * An welchem Punkt müssen RF-Off, Autosave und Bedienereingriffe wirken? Für das Beispiel ist ``AmplifierTest`` bereits vorhanden. Der direkte Aufbau besteht aus Signalgenerator, Verstärker, Ausgangspfad und Leistungsmesser. .. figure:: ../../_static/tutorial/amplifier-direct-setup.svg :alt: Direkter Verstärkermessaufbau mit Signalgenerator, Verstärker, Kabel, Dämpfungsglied und Leistungsmesser :width: 100% Physikalische Sicht auf den direkten Verstärkermessaufbau. Kabel und Dämpfungsglied schützen den Leistungsmesser und werden bei der Pfadkorrektur berücksichtigt. 2. Virtuelle Ablaufkonfiguration -------------------------------- Die ``conf.py`` ist die oberste Ebene der Anwendung. Sie legt Dateien, Suchpfade sowie Mess- und Auswerteparameter fest. Frequenzen sind in Hz angegeben; Pegel werden als Quantities übergeben: .. code-block:: python from scuq.quantities import Quantity from scuq.si import WATT measure_parameters = [{ "dotfile": "amplifier-test-direct-virtual.dot", "SearchPaths": [str(CONF_DIR), str(COMMON_CONF_DIR)], "freqs": [150e6, 240e6], "levels": [ Quantity(WATT, dBm2W(level)) for level in (-40, -35, -30) ], "measurement_setup": "direct", "names": { "sg": "Sg", "amp_in": "Amp_Input", "amp_out": "Amp_Output", "pm_out": "Pm", }, "virtual": True, }] Ausgabe-, Log- und Autosave-Dateien gehören in ein eigenes, ignoriertes ``output``-Verzeichnis. Dadurch bleiben Quellbaum und Testläufe sauber. Die vorhandene Referenz kann direkt ausgeführt werden: .. code-block:: console python script/amplifier-test.py \ script/conf/amplifier-test-direct-virtual/conf.py 3. Gerätetopologie im DOT-Graph ------------------------------- Der DOT-Graph beschreibt Geräte und HF-Pfade, nicht den Ablauf der Frequenzschleife. Logische Namen aus der Messklasse werden über ``names`` auf Knoten im Graph abgebildet. Frequenzabhängige Zweige verwenden einen ausdrücklichen Namen wie ``FREQUENCY``: .. code-block:: dot digraph { Sg [ini="sg-virtual.ini"] Amp [ini="amp-virtual.ini"] Pm [ini="pm-virtual.ini"] PathSgAmp [ini="path-loss-virtual.ini"] CableAmpPm [ini="path-loss-virtual.ini"] Attenuator [ini="attenuator-40db-virtual.ini"] Sg -> Amp_Input [dev=PathSgAmp what="S21"] Amp_Input -> Amp_Output [dev=Amp what="S21"] Amp_Output -> AmpPmAfterCable [dev=CableAmpPm what="S21"] AmpPmAfterCable -> Pm [dev=Attenuator what="S21"] } .. figure:: ../../_static/tutorial/amplifier-direct-graph.svg :alt: Grafische Darstellung des DOT-Graphen für den direkten Verstärkertest :width: 100% Grafische Sicht auf den DOT-Graphen. Messpositionen werden als Knoten dargestellt; die Attribute ``dev`` und ``what`` ordnen jeder Kante das Korrekturelement und dessen Übertragungsgröße zu. Der reale DOT-Graph ergänzt Frequenz-Conditions und weitere Geräteattribute. Diese ändern die Zuordnung, nicht die Trennung zwischen Messpositionen und Pfadkorrekturen. Die :doc:`DOT-Referenz <../configuration/dot>` beschreibt alle verwendeten Attribute, den Condition-Kontext, sichere Actions und die zustandsfreie Pfadprüfung. In Python wertet ``MGraph`` Conditions mit einem expliziten Kontext aus: .. code-block:: python from mpylab.tools.mgraph import FREQUENCY_CONDITION_MAP, MGraph graph = MGraph( dotfile, names, SearchPaths=search_paths, condition_map=FREQUENCY_CONDITION_MAP, allow_legacy_condition_context=False, ) graph.EvaluateConditions(context={"frequency": frequency}) Die Suche nach einer zufällig gleich benannten Variablen in äußeren Python-Frames ist nur eine Legacy-Rückfallebene und sollte in neuen Anwendungen deaktiviert werden. 4. Geräteinstanzen in INI-Dateien --------------------------------- Jeder instrumentierte DOT-Knoten verweist auf eine INI-Datei. Diese wählt den Treiber, den Kanal, Gerätegrenzen und bei Bedarf DAT-Dateien aus. Virtuelle Treiber haben dieselbe öffentliche Geräte-API wie reale Treiber. Der Wechsel zu Hardware soll deshalb überwiegend durch andere INI- und DOT-Dateien erfolgen, nicht durch eine zweite Messroutine. Die :doc:`INI- und DAT-Referenz <../configuration/instrument-data>` erklärt die Kanalstruktur, Fehlerangaben und komplexen Korrekturwerte. Sicherheitsgrenzen wie ``MAXIN`` gehören zur Geräte- oder Verstärkerkonfiguration. Sie dürfen nicht erst in der Oberfläche geprüft werden. 5. Messwerte und Auswertung --------------------------- Messwerte werden mit Einheit und Unsicherheit als SCUQ-Quantities geführt. Eine Umwandlung in ``float`` ist auf Geräteprotokolle, numerische Schnittstellen und die abschließende Darstellung zu begrenzen. Gemeinsame Umrechnungen erfolgen über ``mpylab.tools.uconv``. Rohdaten und Auswertedaten erhalten stabile, fachlich benannte Strukturen. Die Beschreibung einer Messung bildet dabei einen Datensatzschlüssel; die Frequenz ist innerhalb des Datensatzes der bevorzugte Index. So können Pickle-Dateien später direkt mit pexplorer und den Reportmodulen untersucht werden. 6. Autosave und Fortsetzen -------------------------- Lange Messungen müssen nach dem letzten vollständig gemessenen Punkt fortgesetzt werden können. Eine Messroutine speichert deshalb nicht nur Daten, sondern auch eine strukturierte Wiederanlaufinformation: .. code-block:: python self.set_autosave_resume( measurement="amplifier-test", method="Measure", description=description, ) self.do_autosave() Beim Laden ist ``load_pickle_compat`` zu verwenden: .. code-block:: python from mpylab.env.Measure import load_pickle_compat measurement = load_pickle_compat(autosave_filename) Der zugehörige Test muss nachweisen, dass bereits vorhandene Frequenz- und Pegelwerte nicht erneut gemessen werden. Nur das erfolgreiche Laden eines Pickles zu testen, reicht nicht aus. 7. Tests ohne Hardware ---------------------- Ein neuer Ablauf benötigt mindestens: * einen Konfigurationstest, der Graph und virtuelle Geräte initialisiert; * einen kurzen End-to-End-Test mit wenigen Frequenzen und Pegeln; * einen Autosave-/Resume-Test; * Tests für Gerätegrenzen und RF-Off; * einen Test für fehlende oder mehrdeutige aktive Graphpfade. Der virtuelle Test soll dieselben öffentlichen Methoden aufrufen wie der spätere Hardwarelauf. Mocks sind vor allem für gezielte Fehlerfälle sinnvoll, nicht als Ersatz für den virtuellen End-to-End-Ablauf. 8. UI ergänzen -------------- Die Messroutine bleibt unabhängig von Text- oder Qt-Oberfläche. Eine GUI startet blockierende Geräte- und Messaufrufe in einem Worker. Fortschritt, Messwerte und Zustände gelangen über Signale oder Callbacks in den UI-Thread. RF-Off und manuelle EUT-Intervention müssen jederzeit erreichbar bleiben. Sie sind Teil des Sicherheits- und Bedienkonzepts und dürfen nicht hinter einer blockierten Ereignisschleife liegen. 9. Übergang zu Hardware ----------------------- Vor dem ersten Hardwarelauf wird die virtuelle Konfiguration kopiert und nur auf der Konfigurationsebene angepasst. Danach folgen: #. Graph und Frequenzgrenzen ohne Geräteaktion prüfen. #. Initialisierung bei ausgeschalteter HF testen. #. RF-Off und Schutzgrenzen gezielt auslösen. #. Einen kurzen Lauf mit wenigen Frequenzen durchführen. #. Autosave erzeugen und den Wiederanlauf praktisch prüfen. #. Erst danach den vollständigen Messbereich freigeben. Dieses Vorgehen hält den fachlichen Messablauf für virtuelle und reale Geräte identisch und macht Unterschiede in der Hardwarekonfiguration sichtbar.