bscan added s11
This commit is contained in:
@@ -22,7 +22,7 @@ class TraceRecord:
|
||||
monotonic_ns: int
|
||||
stage_index: int
|
||||
frequency_hz: np.ndarray
|
||||
s21: np.ndarray
|
||||
samples: np.ndarray
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -64,12 +64,20 @@ def _pick_trace_meta(meta: dict[str, Any], input_index: int, output_index: int)
|
||||
return None
|
||||
|
||||
|
||||
def _normalize_channel(channel: str) -> str:
|
||||
normalized = str(channel).strip().lower()
|
||||
if normalized not in {"s21", "s11"}:
|
||||
raise ValueError("channel must be either 's21' or 's11'")
|
||||
return normalized
|
||||
|
||||
|
||||
def _load_stage_records(
|
||||
snapshot_dir: Path,
|
||||
stage: str,
|
||||
*,
|
||||
input_index: int,
|
||||
output_index: int,
|
||||
channel: str,
|
||||
) -> list[TraceRecord]:
|
||||
stage_dir = snapshot_dir / stage
|
||||
records: list[TraceRecord] = []
|
||||
@@ -85,20 +93,20 @@ def _load_stage_records(
|
||||
continue
|
||||
|
||||
freq_file = str(trace_meta.get("freq_file", ""))
|
||||
s21_file = str(trace_meta.get("s21_file", ""))
|
||||
if not freq_file or not s21_file:
|
||||
samples_file = str(trace_meta.get(f"{channel}_file", ""))
|
||||
if not freq_file or not samples_file:
|
||||
continue
|
||||
|
||||
frequency_hz = np.asarray(np.load(collection_dir / freq_file), dtype=np.float64).reshape(-1)
|
||||
s21 = np.asarray(np.load(collection_dir / s21_file), dtype=np.complex128).reshape(-1)
|
||||
if frequency_hz.shape != s21.shape:
|
||||
raise ValueError(f"Shape mismatch in {collection_dir}: freq{frequency_hz.shape} vs s21{s21.shape}")
|
||||
samples = np.asarray(np.load(collection_dir / samples_file), dtype=np.complex128).reshape(-1)
|
||||
if frequency_hz.shape != samples.shape:
|
||||
raise ValueError(f"Shape mismatch in {collection_dir}: freq{frequency_hz.shape} vs {channel}{samples.shape}")
|
||||
if frequency_hz.size == 0:
|
||||
continue
|
||||
if not (
|
||||
np.isfinite(frequency_hz).all()
|
||||
and np.isfinite(np.real(s21)).all()
|
||||
and np.isfinite(np.imag(s21)).all()
|
||||
and np.isfinite(np.real(samples)).all()
|
||||
and np.isfinite(np.imag(samples)).all()
|
||||
):
|
||||
raise ValueError(f"Non-finite values in {collection_dir}")
|
||||
|
||||
@@ -109,7 +117,7 @@ def _load_stage_records(
|
||||
monotonic_ns=int(meta.get("monotonic_ns", 0)),
|
||||
stage_index=_parse_stage_index(collection_dir.name, fallback_idx),
|
||||
frequency_hz=frequency_hz,
|
||||
s21=s21,
|
||||
samples=samples,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -157,6 +165,7 @@ def _build_sweep_history(
|
||||
raw_records: list[TraceRecord],
|
||||
preprocessed_records: list[TraceRecord],
|
||||
*,
|
||||
channel: str,
|
||||
primary_stage: str,
|
||||
) -> list[dict[str, Any]]:
|
||||
raw_map, raw_order = _index_by_collection_occurrence(raw_records)
|
||||
@@ -188,11 +197,11 @@ def _build_sweep_history(
|
||||
history.append(
|
||||
{
|
||||
"timestamp": timestamp_sec,
|
||||
"sweep_points": _complex_to_points(sweep_source.s21),
|
||||
"calibrated_points": _complex_to_points(calibrated_source.s21),
|
||||
"sweep_points": _complex_to_points(sweep_source.samples),
|
||||
"calibrated_points": _complex_to_points(calibrated_source.samples),
|
||||
"reference_points": [],
|
||||
"vna_config": {
|
||||
"mode": "s11",
|
||||
"mode": channel,
|
||||
"start_freq": start_freq_hz,
|
||||
"stop_freq": stop_freq_hz,
|
||||
"points": int(base.frequency_hz.size),
|
||||
@@ -257,6 +266,12 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
)
|
||||
parser.add_argument("--input", dest="input_index", type=int, default=0, help="Input switch index to export.")
|
||||
parser.add_argument("--output-index", dest="output_index", type=int, default=0, help="Output switch index to export.")
|
||||
parser.add_argument(
|
||||
"--channel",
|
||||
choices=("s21", "s11"),
|
||||
default="s21",
|
||||
help="Trace channel to export into sweep/calibrated points.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--primary-stage",
|
||||
choices=("preprocessed", "raw"),
|
||||
@@ -275,6 +290,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
||||
def main() -> None:
|
||||
parser = _build_parser()
|
||||
args = parser.parse_args()
|
||||
channel = _normalize_channel(args.channel)
|
||||
|
||||
snapshot_dir = args.snapshot_dir.expanduser().resolve()
|
||||
if not snapshot_dir.exists():
|
||||
@@ -291,12 +307,14 @@ def main() -> None:
|
||||
"raw",
|
||||
input_index=args.input_index,
|
||||
output_index=args.output_index,
|
||||
channel=channel,
|
||||
)
|
||||
preprocessed_records = _load_stage_records(
|
||||
snapshot_dir,
|
||||
"preprocessed",
|
||||
input_index=args.input_index,
|
||||
output_index=args.output_index,
|
||||
channel=channel,
|
||||
)
|
||||
if not raw_records and not preprocessed_records:
|
||||
raise ValueError(
|
||||
@@ -304,7 +322,12 @@ def main() -> None:
|
||||
f"for input={args.input_index}, output={args.output_index}."
|
||||
)
|
||||
|
||||
sweep_history = _build_sweep_history(raw_records, preprocessed_records, primary_stage=args.primary_stage)
|
||||
sweep_history = _build_sweep_history(
|
||||
raw_records,
|
||||
preprocessed_records,
|
||||
channel=channel,
|
||||
primary_stage=args.primary_stage,
|
||||
)
|
||||
if args.last_n > 0:
|
||||
sweep_history = sweep_history[-args.last_n :]
|
||||
if not sweep_history:
|
||||
@@ -324,6 +347,7 @@ def main() -> None:
|
||||
"source_snapshot_dir": str(snapshot_dir),
|
||||
"input_index": int(args.input_index),
|
||||
"output_index": int(args.output_index),
|
||||
"channel": channel,
|
||||
"primary_stage": args.primary_stage,
|
||||
"raw_record_count": len(raw_records),
|
||||
"preprocessed_record_count": len(preprocessed_records),
|
||||
@@ -341,6 +365,7 @@ def main() -> None:
|
||||
"Converted snapshot to vna_system history JSON:\n"
|
||||
f" input snapshot: {snapshot_dir}\n"
|
||||
f" output file: {output_path}\n"
|
||||
f" channel: {channel}\n"
|
||||
f" sweeps written: {len(sweep_history)}\n"
|
||||
f" raw records: {len(raw_records)}\n"
|
||||
f" pre records: {len(preprocessed_records)}"
|
||||
|
||||
Reference in New Issue
Block a user