Add RawFile.resolve_index, dedup signal-index lookup in two tools

tune_circuit and plot_waveform each hand-rolled exact case-insensitive
name->row-index resolution -- a manual 3-way loop and a next(enumerate)
generator respectively. Centralize as RawFile.resolve_index(), next to
the existing get_variable() (which does partial match, so it can't be
reused here without changing semantics).

No behavior change: exact case-insensitive match and the not-found error
paths (with available_signals) are preserved. Verified against the live
LTspice path -- tune_circuit bandwidth and plot_waveform resolution
unchanged.
This commit is contained in:
Ryan Malloy 2026-06-19 22:53:14 -06:00
parent 351b89ada5
commit d177a8a316
2 changed files with 21 additions and 16 deletions

View File

@ -52,6 +52,19 @@ class RawFile:
return arr
return None
def resolve_index(self, name: str) -> int | None:
"""Return a variable's data-row index by exact name (case-insensitive).
Unlike get_variable (partial match, returns the data array), this does an
exact case-insensitive name match and returns the integer row index into
self.data, or None if there's no exact match.
"""
name_lower = name.lower()
for var in self.variables:
if var.name.lower() == name_lower:
return var.index
return None
def get_time(self, run: int | None = None) -> np.ndarray | None:
"""Get the time axis (for transient analysis)."""
return self.get_variable("time", run=run)

View File

@ -1272,17 +1272,10 @@ async def tune_circuit(
if raw is None:
return {"error": "No raw data from simulation", "params_used": effective_params}
# Find the signal variable
sig_idx = None
time_idx = None
freq_idx = None
for var in raw.variables:
if var.name.lower() == signal.lower():
sig_idx = var.index
if var.name.lower() == "time":
time_idx = var.index
if var.name.lower() == "frequency":
freq_idx = var.index
# Find the signal variable (exact, case-insensitive)
sig_idx = raw.resolve_index(signal)
time_idx = raw.resolve_index("time")
freq_idx = raw.resolve_index("frequency")
if sig_idx is None:
available = [v.name for v in raw.variables]
@ -1513,19 +1506,18 @@ async def plot_waveform(
signal_list = signals if signals else [signal]
is_multi = len(signal_list) > 1
# Resolve all signal names (case-insensitive)
# Resolve all signal names (exact, case-insensitive)
sig_names = [v.name for v in raw_data.variables]
sig_lower = {s.lower(): s for s in sig_names}
resolved: list[tuple[str, int]] = [] # (actual_name, index)
for s in signal_list:
actual = sig_lower.get(s.lower())
if actual is None:
idx = raw_data.resolve_index(s)
if idx is None:
return {
"error": f"Signal '{s}' not found",
"available_signals": sig_names,
}
idx = next(i for i, v in enumerate(raw_data.variables) if v.name == actual)
resolved.append((actual, idx))
resolved.append((sig_lower[s.lower()], idx))
# Get x-axis data (time or frequency)
x_var = raw_data.variables[0]