DOT-Referenz für Messgraphen¶
Eine DOT-Datei beschreibt aktive Geräte, passive Korrekturelemente und ihre
Verbindungen. Sie ist kein Ablaufprogramm: Frequenzschleifen,
Bedienerinteraktion und Auswertung bleiben Aufgabe der Messklasse. Die
mpylab.tools.mgraph.MGraph-Instanz verbindet den Graphen mit
Geräteerzeugung, Conditions, Schaltaktionen und Pfadkorrekturen.
Produktiver Parser und Eingaben¶
MGraph verwendet pydot als verbindlichen produktiven Parser. Es
akzeptiert:
einen Dateinamen oder ein
os.PathLike-Objekt;ein lesbares dateiähnliches Objekt;
direkten DOT-Text;
strukturierte pydot-kompatible Graphdaten.
Relative Dateinamen werden in SearchPaths gesucht. Eine nicht gefundene
Datei, ungültiger DOT-Text oder mehrere aneinandergehängte Graphen lösen
mpylab.tools.mgraph.GraphInputError aus. Ein Messgraph enthält genau
einen graph oder digraph.
from mpylab.tools.mgraph import MGraph
graph = MGraph(
"measurement.dot",
SearchPaths=["lab/config", "shared/config"],
)
Pickle und Rückverfolgbarkeit¶
Beim Pickeln wird der vollständige DOT-Text im MGraph gespeichert. Beim
Wiederherstellen ist dieser eingebettete Text maßgeblich; die ursprüngliche
Datei wird nicht erneut gelesen. Eine Messhistorie bleibt dadurch auch dann
reproduzierbar, wenn die lokale DOT-Datei fehlt oder später geändert wurde.
Der ursprüngliche Dateiname bleibt in fname_or_data als Herkunft erhalten.
Unterstützter DOT-Teilumfang¶
Der in mpylab verwendete Teilumfang umfasst insbesondere:
graph,digraphsowie die optionalestrict-Kennzeichnung;Knoten- und Kantenanweisungen;
eine oder mehrere Attributlisten in
[...];gerichtete
->und ungerichtete--Verbindungen;IDs, Zahlen und gequotete Strings;
#-,//- und/* ... */-Kommentare.
Für Messgraphen wird üblicherweise ein digraph verwendet.
Knoten und Kanten¶
digraph {
Sg [ini="sg.ini"]
Amp [ini="amplifier.ini"
condition="FREQUENCY <= 1e9"]
Cable [ini="cable.ini"]
Sg -> Amp_Input
Amp_Input -> Amp_Output [dev=Amp what="S21"]
Amp_Output -> Pm [dev=Cable what="S21"]
}
Wichtige Attribute sind:
iniKonfiguration einer Geräteinstanz. Der Dateiname wird über
SearchPathsaufgelöst.devGeräteknoten, dessen Kanal eine Kante beschreibt. Der Knoten muss im Graph ausdrücklich deklariert sein.
whatName des Datenkanals, beispielsweise
S21. Das Attribut darf fehlen, wenn eine Kante das Gerät bewusst ohne Datenkanal referenziert.conditionBoolescher Ausdruck, der Knoten oder Kante aktiviert.
actionSicher begrenzter Methodenaufruf, der beim Aktivieren eines Elements mit Condition ausgeführt werden kann.
context_controllerKennzeichnet ein Gerät, das logische Context-Werte auf einen physischen Schaltzustand abbildet und diesen zurückliest. Der Wert benennt die für eine erneute Anwendung relevanten Context-Schlüssel, beispielsweise
context_controller="mode".
Reine Verbindungs- oder Messpositionsknoten benötigen keine INI-Datei. Aufbau, Einheiten und DAT-Verweise der Gerätekanäle beschreibt die INI- und DAT-Referenz.
Gerätetypen und Treiber¶
DESCRIPTION/TYPE in der INI-Datei benennt die Einstiegsklasse, die das
unter DESCRIPTION/DRIVER angegebene Modul exportiert. Kanonische Typen
entsprechen den Gerätebasisklassen, beispielsweise SIGNALGENERATOR,
POWERMETER, FIELDPROBE, RECEIVER, SPECTRUMANALYZER,
NETWORKANALYZER, VLISN und TLISN.
Die Auflösung ignoriert Groß-/Kleinschreibung und historische umschließende
Anführungszeichen, verwendet aber kein unscharfes String-Matching. Für
TYPE = Custom müssen zusätzlich DRIVER und CLASS angegeben sein;
das Modul wird aus SearchPaths geladen.
Fehlende INI- oder Treiberdateien, unbekannte Typen und fehlende
Einstiegsklassen lösen
mpylab.tools.mgraph.DeviceConfigurationError aus. CreateDevices
erzeugt nur Python-Treiberinstanzen. Der Hardwarezugriff beginnt erst mit
Init_Devices.
Aktive Geräte auswählen¶
Geräteoperationen wie Init_Devices, SetFreq_Devices,
ConfReceivers, RFOff_Devices und RunReceiverScans verwenden
einheitlich IgnoreInactive=True als Standard. Damit werden nur die durch
die aktuellen Conditions aktiven Geräteknoten angesprochen. Mit
IgnoreInactive=False werden bewusst auch inaktive, aber konfigurierte
Geräte einbezogen. Dies ist beispielsweise für eine vollständige Diagnose
oder ein ausdrücklich graphweites Aufräumen sinnvoll.
Namen-Mapping¶
Die Messklasse verwendet fachliche Rollen wie sg, pm_out oder
fieldprobe. Das names-Dictionary aus conf.py wird als themap
an MGraph übergeben:
names = {
"sg": "Sg",
"pm_out": "Pm",
"fieldprobe": ["Probe1", "Probe2"],
}
graph = MGraph(dotfile, themap=names)
Die verbindliche Richtung lautet logischer Name -> DOT-Knoten. Leere
Listen sind für optionale Rollen zulässig. Beim Laden historischer Pickles
normalisiert MGraph eindeutig erkennbare umgekehrte oder bidirektionale
Mappings.
Die semantische Prüfung lehnt unbekannte Mapping-Ziele und dev-Referenzen
ab. Nach CreateDevices wird zusätzlich geprüft, ob für jedes referenzierte
Gerät tatsächlich eine Treiberinstanz existiert.
Feldsondenorientierung¶
Feldsondentreiber liefern ihre drei Komponenten immer als
[probe_x, probe_y, probe_z]. Die Abbildung in Zellkoordinaten gehört zur
Messkonfiguration und wird bevorzugt am Feldsondenknoten im DOT-Graphen
angegeben. Eine signierte Achsvertauschung lautet beispielsweise:
Probe [probe_axis_map="cell_x:-probe_y,cell_y:+probe_x,cell_z:+probe_z"]
Für allgemeine Verdrehungen kann eine eigentliche orthonormale
Rotationsmatrix mit Determinante +1 angegeben werden. Sie bildet den
Sondenvektor auf den Zellvektor ab:
Probe [probe_rotation_matrix="0,-1,0;1,0,0;0,0,1"]
Alternativ stehen die anschaulicheren festen Zellachsenwinkel
probe_rotation_angles_deg zur Verfügung. Die Reihenfolge ist Drehung um
Zell-z, danach Zell-x und zuletzt Zell-y. Orientierungseinträge können auch
aus dem Konfigurations-Dictionary oder der Feldsonden-INI kommen. Werden
widersprüchliche Angaben gefunden, muss die Auswahl ausdrücklich aufgelöst
werden; eine stillschweigende Doppelkorrektur findet nicht statt.
Conditions und expliziter Kontext¶
Neue Graphen verwenden stabile Namen wie FREQUENCY. condition_map
trennt diese Namen von Variablen im Anwendungsprogramm:
from mpylab.tools.mgraph import FREQUENCY_CONDITION_MAP, MGraph
graph = MGraph(
dotfile,
condition_map=FREQUENCY_CONDITION_MAP,
allow_legacy_condition_context=False,
)
graph.EvaluateConditions(context={"frequency": current_frequency})
AmpLF [condition="80e6 <= FREQUENCY <= 1e9"]
AmpHF [condition="1e9 < FREQUENCY <= 6e9"]
FREQUENCY_CONDITION_MAP akzeptiert während der Migration sowohl f als
auch FREQUENCY und bildet beide auf frequency ab. Gepflegte Graphen
verwenden FREQUENCY. Fehlende Namen, ungültige Ausdrücke oder Ergebnisse,
die nicht boolesch sind, lösen
mpylab.tools.mgraph.ConditionContextError aus.
Ohne expliziten Kontext kann EvaluateConditions aus
Kompatibilitätsgründen noch im Aufrufer-Frame suchen. Dieser veraltete Weg
erzeugt einmal pro Graphinstanz eine
mpylab.tools.mgraph.LegacyConditionContextWarning. Neue Anwendungen
schalten ihn mit allow_legacy_condition_context=False ab. Kontext-Mapping
und diese Einstellung werden im Pickle gespeichert.
Physische Context-Controller¶
Wenn ein Messgraph außer der Auswahl aktiver Pfade auch einen physischen Aufbau umschalten muss, kapselt ein Context-Controller diese Abbildung. Die Anwendung übergibt weiterhin ausschließlich logische Werte:
from mpylab.tools.mgraph import MGraph, TEM_CONDITION_MAP
graph = MGraph(
dotfile,
condition_map=TEM_CONDITION_MAP,
allow_legacy_condition_context=False,
)
graph.CreateDevices()
graph.Init_Devices()
result = graph.ApplyContext({
"frequency": 150e6,
"mode": "GTEM",
})
sw [ini="sw_gtem.ini" context_controller="mode"]
source -> gtem [condition="MODE == 'GTEM'"]
source -> term [condition="MODE == 'TERM'"]
Der Gerätetreiber implementiert dafür PrepareGraphContext(context),
ApplyGraphContext(context) und GetGraphState(). Optional kann
GraphStateMatches(expected, actual) die fachliche Gleichheit definieren.
PrepareGraphContext muss den vollständigen erwarteten Zustand liefern,
nicht nur das zuletzt geschaltete Relais. GetGraphState muss den realen
Zustand abfragen; eine unvollständige oder nicht auswertbare Antwort ist kein
Erfolg.
ApplyContext schaltet RF vor einer relevanten Context- oder
Frequenzänderung aus, wendet nötige Controlleränderungen an, wertet Conditions
aus, setzt die Frequenz und verifiziert anschließend die Rücklesewerte. Die im
Attribut genannten Schlüssel steuern, wann ApplyGraphContext erneut
aufgerufen wird. Bei
context_controller="mode" löst daher ein Frequenzwechsel allein keine
erneute Mode-Umschaltung aus; der aktuelle vollständige Schaltzustand wird
trotzdem geplant und geprüft.
Eine Zustandsabweichung löst
mpylab.tools.mgraph.GraphStateMismatchError aus und schaltet RF aus.
CheckContextState prüft sofort, PollContextState kann die Abfragen
zeitlich begrenzen. RFOn_Devices, Read und NBRead führen diese
Prüfung an ihren sicheren Programmpunkten aus. Nur ein ausdrücklicher
Bedienerentscheid sollte anschließend ReapplyContext aufrufen; allgemeine
Messanwendungen dürfen den konkreten Schaltertyp nicht kennen.
Sichere Actions¶
Ein aktives Element mit condition kann zusätzlich eine action tragen:
SwitchLF [condition="FREQUENCY <= 1e9"
action="switch.switch_to(0)"]
graph.EvaluateConditions(context={
"frequency": frequency,
"switch": switch_instance,
})
Zulässig ist genau ein direkter Methodenaufruf auf einem Objekt aus dem
Kontext mit literalen Argumenten. Beliebiger Python-Code, Attributketten als
Argumente und mehrere Anweisungen werden abgelehnt. doAction=False wertet
nur den Graphzustand aus und schaltet keine Hardware. Das ist der richtige
Modus für Preflight und Pfadprüfung.
Pfadprüfung¶
mpylab.tools.mgraph.MGraph.check_paths() prüft Conditions über einen
Parameterbereich, ohne Actions auszuführen oder den Graphzustand zu ändern:
report = graph.check_paths(
"Sg",
"TxAnt",
"frequency",
start_value=80e6,
stop_value=6e9,
context={"measurement_mode": "immunity"},
)
if not report.ok:
print(report.format_text())
Der Standardmodus exactly_one_path verlangt genau einen vollständigen
aktiven Pfad. mode="warn_parallel" stuft mehrere vollständige Pfade zur
Warnung herab; ein fehlender Pfad bleibt ein Fehler. Aktive abzweigende
Teilpfade werden ebenfalls gemeldet.
Einfache Vergleiche werden grenzwertbewusst geprüft: Neben dem Grenzwert
werden die unmittelbar kleineren und größeren Gleitkommawerte getestet. So
werden </<=-Lücken und Überlappungen erkannt. Tatsächliche Messpunkte
können mit values=frequencies ergänzt werden. Bei komplexeren Ausdrücken
ist keine vollständige statische Grenzanalyse möglich;
report.boundary_analysis_complete ist dann False.
Für einen einzelnen Kontext liefert active_paths die aktiven Pfade
ebenfalls zustandsfrei. Die Anwendung von Korrekturen wird unter
Pfadkorrekturen beschrieben.
Lokale DOT-Dateien migrieren¶
mpylab-dot-migrate ersetzt das historische Condition-Token f durch
FREQUENCY. Der Standard ist ein Dry-Run mit Syntaxprüfung und Unified Diff:
mpylab-dot-migrate local-config.dot
mpylab-dot-migrate --write local-config.dot
mpylab-dot-migrate --check --recursive path/to/configurations
Nur das exakte Namenstoken in condition wird geändert. Kommentare,
Labels, Dateinamen, Stringliterale und action bleiben unverändert.
--write schreibt atomar; Verzeichnisse werden nur mit --recursive
durchlaufen. Symbolischen Links wird nicht gefolgt.
Für CI liefert --check Status 1 bei nötiger Migration und Status 2 bei
ungültigen Eingaben. Pfadprüfungen können direkt ergänzt werden:
mpylab-dot-migrate \
--path Sg:TxAnt \
--frequency-range 80e6 6e9 \
--path-mode exactly_one_path \
--context "MODE='immunity'" \
local-config.dot
Alle Optionen stehen in der CLI-Referenz.
Konfigurations-Repositories prüfen¶
Viele produktive Graphen sollten in einer versionskontrollierten Manifestdatei inventarisiert werden. Benannte TOML-Tabellen können erwartete Gerätezahl, erlaubte Rückfallebenen und fachliche Pfadprüfungen festhalten:
[configurations.large_gtem_immunity]
dot = "LargeGTEM/dot/gtem-immunity.dot"
expected_device_count = 15
allowed_fallback_modules = []
[[configurations.large_gtem_immunity.path_checks]]
start = "sg"
end = "gtem"
parameter = "frequency"
start_value = 1.0e6
stop_value = 4.2e9
Das Manifest gehört zum jeweiligen Konfigurations-Repository, nicht zum
MGraph-Dateiformat. Generische Tests können damit vollständige Erfassung,
auflösbare INI-Verweise, Geräteerzeugung und Pfadprüfungen sicherstellen.
Unfertige Graphen gehören in einen ausdrücklich gekennzeichneten Bereich.
Weitere Prüfungen beschreibt Konfigurationen prüfen und migrieren.
Unabhängiger Parser¶
mpylab.tools.dotparser implementiert den benötigten DOT-Teilumfang nur
mit der Python-Standardbibliothek. MGraph wählt ihn nicht automatisch und
verwendet produktiv weiterhin pydot. Der unabhängige Parser dient als
Vergleichsimplementierung und mögliche Grundlage späterer Entwicklungen.
Tests lesen die eingecheckten Graphen mit beiden Parsern und vergleichen
Knoten, Kanten und Attribute. Der frühere, aus dot.g erzeugte
Yapps-Parser war nie an den produktiven MGraph-Pfad angebunden und wurde
zusammen mit seiner Laufzeitabhängigkeit entfernt.
Weiterführende Seiten¶
INI- und DAT-Referenz für Gerätedaten für INI-Kanäle und DAT-Korrekturdaten;
Konfigurationen prüfen und migrieren für Konfigurations- und CI-Prüfungen;
Conditions, Schaltmatrix und Pfadkorrekturen für Berechnung und Anwendung von Pfadkorrekturen;
Measurement graph für die kuratierte
MGraph-API.