Conditions, Schaltmatrix und Pfadkorrekturen

Pfadkorrekturen verbinden die in einem DOT-Graph beschriebenen Übertragungswege mit den tatsächlich gemessenen Größen. Bei frequenzabhängigen Messaufbauten müssen drei Schritte zusammenpassen:

  1. aktive Graphzweige auswählen;

  2. reale Geräte und Schaltmatrix auf die Frequenz einstellen;

  3. die Korrektur des aktiven Pfades lesen und anwenden.

Knoten, Kanten, Conditions und dev/what-Attribute sind in der DOT-Referenz vollständig beschrieben.

Die Korrekturwerte selbst werden typischerweise durch einen INI-Kanal und eine DAT-Datei bereitgestellt. Syntax, Einheiten, komplexe Werte und Unsicherheiten stehen in der INI- und DAT-Referenz.

Conditions auswerten

EvaluateConditions aktiviert Knoten und Kanten anhand des expliziten Kontexts:

mg.EvaluateConditions(context={"frequency": frequency})

Mit doAction=False wird nur der Graphzustand berechnet. Das ist für Preflight, Scanplanung und Pfadprüfung wichtig, weil dabei keine Hardware geschaltet werden darf.

Ein aktives Element kann zusätzlich ein action-Attribut besitzen. Ausgeführt wird ausschließlich ein direkter Methodenaufruf auf einem Objekt aus dem Kontext mit literalen Argumenten. Beliebiger Python-Code ist nicht zulässig. Actions eignen sich für kleine, ausdrücklich konfigurierte Zustandswechsel; gerätespezifische Schaltlogik gehört bevorzugt in den Treiber.

Eine kleine Matrix kann alternativ direkt über Actions geschaltet werden:

SwitchLF [condition="FREQUENCY <= 1e9"
          action="switch.switch_to(0)"]
SwitchHF [condition="FREQUENCY > 1e9"
          action="switch.switch_to(1)"]
mg.EvaluateConditions(context={
    "frequency": frequency,
    "switch": switch_instance,
})

Diese Variante und ein frequenzabhängiges SetFreq im Switch-Treiber sind Alternativen. Derselbe Relaiszustand soll nicht über beide Wege gleichzeitig gesetzt werden.

Switch-Matrix über SetFreq

Eine Switch-Matrix ist ein reguläres Gerät im MGraph. Ihr Treiber implementiert SetFreq(frequency) und wählt anhand seiner INI-Konfiguration den erforderlichen Relaiszustand. SetFreq_Devices ruft diese Methode zusammen mit den anderen frequenzabhängigen Geräten auf:

mg.EvaluateConditions(context={"frequency": frequency})
mg.SetFreq_Devices(frequency)

Die Conditions und die Schaltschwelle des Treibers müssen dieselben Bereichsgrenzen verwenden. Der Graph wählt beispielsweise den LF-Zweig bis einschließlich 1 GHz, während der Switch-Treiber bei f <= 1e9 dieselbe Relaisstellung wählt.

Vor dem Umschalten wird ein Signalgenerator auf einen sicheren Startpegel gesetzt oder RF abgeschaltet. Das ist besonders wichtig, wenn der Frequenzwechsel einen anderen Verstärker mit abweichender Eingangsgrenze aktiviert.

Komplexeres TEM-Beispiel

digraph {
    Switch [ini="sw_gtem.ini"]
    Sg     [ini="sg.ini"]
    AmpLF  [ini="amp-lf.ini"
            condition="FREQUENCY <= 1e9"]
    AmpHF  [ini="amp-hf.ini"
            condition="FREQUENCY > 1e9"]

    PathSgLF   [ini="sg-lf.ini"]
    PathSgHF   [ini="sg-hf.ini"]
    PathLFCell [ini="lf-cell.ini"]
    PathHFCell [ini="hf-cell.ini"]

    Sg -> SgLF [condition="FREQUENCY <= 1e9"]
    Sg -> SgHF [condition="FREQUENCY > 1e9"]

    SgLF -> AmpInLF [dev=PathSgLF what="S21"]
    SgHF -> AmpInHF [dev=PathSgHF what="S21"]
    AmpInLF -> AmpOutLF [dev=AmpLF what="S21"]
    AmpInHF -> AmpOutHF [dev=AmpHF what="S21"]
    AmpOutLF -> GTEM [dev=PathLFCell what="S21"]
    AmpOutHF -> GTEM [dev=PathHFCell what="S21"]
}
Frequenzabhängige LF- und HF-Pfade einer TEM-Verifikation mit Schaltmatrix

Der Condition-Kontext wählt den roten oder blauen Korrekturpfad. Parallel dazu stellt SetFreq_Devices die Switch-Matrix und alle aktiven Geräte auf dieselbe Frequenz ein.

Dieses vereinfachte Beispiel zeigt nur den Vorwärtspfad. Eine reale TEM-Verifikation ergänzt Abzweige zu Vorwärts- und Rückwärtsleistungsmessern sowie deren eigene Koppler- und Kabelkorrekturen.

Gesamtkorrektur lesen

get_path_correction liefert die Gesamtkorrektur zwischen zwei Messpositionen:

from mpylab.tools.aunits import POWERRATIO

correction = mg.get_path_correction(
    names["sg"],
    names["port"],
    POWERRATIO,
)

Ohne unit wird AMPLITUDERATIO verwendet. Bei der Umwandlung eines komplexen Amplitudenverhältnisses in ein Leistungsverhältnis wird abs(S21) ** 2 gebildet. Einheit und Unsicherheit bleiben erhalten.

get_path_corrections gibt zusätzlich die einzelnen Korrekturelemente zurück. Der Schlüssel "total" enthält das Gesamtergebnis:

details = mg.get_path_corrections("Sg", "GTEM")
total = details["total"]

Diese detaillierte Form eignet sich für Diagnose und Reports. Anwendungslogik sollte für die übliche Gesamtkorrektur get_path_correction verwenden.

Kohärente Reihen- und Parallelpfade

Alle aktiven Pfade werden unabhängig von der angeforderten Ausgabeeinheit als komplexe Amplitudenverhältnisse verknüpft:

\[H_p = \prod_{k\in p} S_{21,k},\qquad H = \sum_p H_p,\qquad R_P = |H|^2.\]

POWERRATIO entsteht erst nach dieser Summe und einer eventuellen Division durch einen Referenzpfad. Zwei Beiträge mit Amplitudenbetrag eins ergeben bei 0, 90 und 180 Grad Phasendifferenz somit Leistungsverhältnisse von 4, 2 und 0. In Reihe werden komplexe Amplituden multipliziert; ihre Phasen addieren sich. Gemeinsame Segmente behalten dieselben unsicheren Eingangsgrößen.

Ein S-Parameter-Betrag d in dB entspricht der Amplitude 10**(d/20). Polare DAT-Werte behalten ihre Phase. Die historische DAT-Darstellung POWERRATIO codiert |S21|**2 * exp(1j*phase) und wird vor der Verknüpfung in Amplitude umgerechnet. Sie ist keine physikalische komplexe Leistung. Skalare Betragsdaten setzen implizit Phase null voraus und können die Interferenz eines tatsächlichen Parallelaufbaus nicht bestimmen.

Das Modell setzt kohärente Beiträge einer Quelle, konsistente Wellennormierung und vernachlässigbare oder bereits enthaltene Reflexionseffekte voraus. Teilungs- und Kombinationskoeffizienten müssen in den konfigurierten Übertragungswegen enthalten sein. Der Faktor vier oben bezieht sich auf einen einzelnen Einheitsbeitrag am Summationspunkt; er bedeutet keinen passiven Leistungsgewinn beim Aufteilen einer Quelle. Vollständige S-Matrix-Netzwerke, Fehlanpassung und inkohärente Leistungsaddition liegen außerhalb dieses Modells. Zu den Wellenkonventionen siehe F. Caspers, RF engineering basic concepts: S-parameters.

get_path_correction(end, start) liefert die inverse Korrektur, nicht S12. Ein Nenner null führt zu ZeroDivisionError, eine fehlende Verbindung zu ValueError. get_path_corrections behält null für einen fehlenden Vorwärtspfad und eins für den leeren Pfad eines Knotens zu sich selbst bei. Die Geräteeinträge bleiben die ursprünglichen Größen; nur "total" folgt der angeforderten Einheit. Jeder Gerätekanal wird je Abfrage einmal gelesen, auch bei Quotienten über einen gemeinsamen Vorgänger. Die nächste Abfrage liest erneut, damit Frequenzwechsel keine veralteten Werte verwenden.

Unsicherheit bei Auslöschung

Das Ergebnis behält die Abhängigkeiten der SCUQ-Ausdrücke, statt jeden Pfad durch einen unabhängigen Unsicherheitseingang zu ersetzen. Auch gemischte reelle und komplexe Ausdrücke behalten gemeinsame skalare Eingänge. Die Leistung wird über das kartesische Betragsquadrat mit der Jacobi-Matrix (2*Re(H), 2*Im(H)) berechnet. Dadurch entfällt die problematische Ableitung von abs(H) bei null.

SCUQ propagiert Unsicherheiten weiterhin in erster Ordnung. Bei nomineller Auslöschung ist diese Jacobi-Matrix null, obwohl unabhängige Amplitudenfehler in Realisierungen eine Leistung ungleich null ergeben. Eine verschwindende linearisierte Leistungsunsicherheit belegt daher keine exakte Auslöschung. Für solche Fälle sind die Amplitudenkovarianz und eine geeignete Auswertung höherer Ordnung oder Monte-Carlo-Rechnung erforderlich. Die Regressionstests enthalten analytische Interferenzfälle, Auslöschung gemeinsamer Eingänge und reproduzierbare Monte-Carlo-Vergleiche zur Verdeutlichung dieser Grenze.

Kompatibilität

INI/DAT-Format und Schlüssel der Diagnose-Dictionaries bleiben unverändert. Zuvor addierte eine POWERRATIO-Abfrage Pfadleistungen oder behielt eine codierte Übertragungsphase. Bei parallelen oder phasenbehafteten Pfaden können die korrigierten Ergebnisse deshalb abweichen. Gespeicherte Messwerte werden nicht automatisch umgeschrieben. Eine Neuauswertung verwendet die korrigierte Rechnung. Zurückgegebene Korrekturen behalten SCUQ-Ausdrücke; neue Pickles mit diesen Ausdrücken benötigen eine mpylab-Version mit den Hilfsklassen für Übertragungsausdrücke.

Korrektur anwenden

Die Richtung muss fachlich ausdrücklich gewählt werden:

corrected = mg.apply_path_correction(
    measured,
    correction,
    operation="divide",
    magnitude=True,
    output_unit=VOLT,
)

operation ist "multiply" oder "divide". magnitude=False erhält die Phase; magnitude=True erzeugt eine reelle Betragsgröße mit Unsicherheit.

Schnelle wiederholte Anwendung

Wenn viele Messwerte mit derselben Korrektur verarbeitet werden, kann sie einmal vorbereitet werden:

prepared = mg.prepare_path_correction(
    correction,
    operation="divide",
    magnitude=True,
    output_unit=VOLT,
)

corrected = [
    mg.apply_path_correction(value, prepared)
    for value in measured_values
]

Eine exakt bekannte, konstante Korrektur kann dadurch einen schnellen Skalierungspfad verwenden. Unsichere oder nicht unterstützte Fälle fallen automatisch auf die vollständige SCUQ-Rechnung zurück.

Das vorbereitete Objekt darf nur wiederverwendet werden, solange Frequenz, aktiver Graphpfad und zugrunde liegende Kalibrierdaten unverändert sind. Nach jedem EvaluateConditions oder Frequenzwechsel wird die Pfadkorrektur neu gelesen und gegebenenfalls neu vorbereitet.

Prüfregeln

  • Conditions vor dem Lesen einer Korrektur auswerten.

  • Schaltmatrix und Graph mit identischen Bereichsgrenzen konfigurieren.

  • Grenzfrequenzen auf fehlende oder doppelte Pfade testen.

  • Korrekturen als SCUQ-Quantities führen.

  • Multiplikation oder Division und das Verwerfen der Phase ausdrücklich angeben.

  • Vorbereitete Korrekturen nicht über einen Graphzustandswechsel hinweg wiederverwenden.