GUI: I limit field is the environment input-current limit, no hardcoded 20A
The 20A PSU ceiling was hardcoded and clamped user entries, which breaks benches with a different supply. Now the sweep I limit field IS the max input current allowed for the test environment: used verbatim as the supply CC limit and as the step-rejection / measured-backstop ceiling. Manual supply-current clamp removed; manual CC/CP load gate now checks against the I limit field value. PSU_MAX_CURRENT_A is reduced to INPUT_LIMIT_DEFAULT_A (initial field value only). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+25
-35
@@ -39,11 +39,13 @@ TELEM_DECIMATE = 4 # telemetry display decimation (full rate still recorded
|
||||
MIN_REDRAW_S = 0.4 # throttle canvas redraws
|
||||
STM_EMA_TAU_S = 2.0 # EMA time constant for displayed telemetry values
|
||||
|
||||
# HV supply capability guard: the PSU can source at most this much current.
|
||||
# Load steps whose estimated input draw exceeds it are rejected, regardless
|
||||
# of what the sweep asks for. The estimate is conservative (low assumed
|
||||
# efficiency) so rejection kicks in before the PSU actually current-limits.
|
||||
PSU_MAX_CURRENT_A = 20.0
|
||||
# Input-current guard: the sweep "I limit" field holds the maximum input
|
||||
# current allowed for the test environment (whatever PSU is on the bench --
|
||||
# no hardcoded ceiling). Load steps whose estimated input draw exceeds it
|
||||
# are rejected, regardless of what the sweep asks for. The estimate is
|
||||
# conservative (low assumed efficiency) so rejection kicks in before the
|
||||
# PSU actually current-limits.
|
||||
INPUT_LIMIT_DEFAULT_A = 20.0 # initial I limit field value only
|
||||
VOUT_NOM_V = 48.0 # nominal converter output, fallback when unmeasured
|
||||
EFF_ASSUMED = 0.90 # conservative efficiency for input-current estimates
|
||||
|
||||
@@ -667,7 +669,7 @@ class TestbenchGUI(tk.Tk):
|
||||
row.pack(fill=tk.X, pady=1)
|
||||
ttk.Label(row, text="I limit:", width=10).pack(side=tk.LEFT)
|
||||
self._svi_ilimit = ttk.Entry(row, width=7)
|
||||
self._svi_ilimit.insert(0, f"{PSU_MAX_CURRENT_A:g}")
|
||||
self._svi_ilimit.insert(0, f"{INPUT_LIMIT_DEFAULT_A:g}")
|
||||
self._svi_ilimit.pack(side=tk.LEFT, padx=2)
|
||||
ttk.Label(row, text="settle:").pack(side=tk.LEFT)
|
||||
self._svi_settle = ttk.Entry(row, width=5)
|
||||
@@ -1451,24 +1453,17 @@ class TestbenchGUI(tk.Tk):
|
||||
self._send_float(Cmd.SET_VOLTAGE, self._sup_voltage)
|
||||
|
||||
def _set_supply_current(self) -> None:
|
||||
self._clamp_supply_current_entry()
|
||||
self._send_float(Cmd.SET_CURRENT, self._sup_current)
|
||||
|
||||
def _clamp_supply_current_entry(self) -> None:
|
||||
"""Keep the programmed supply current within PSU capability."""
|
||||
def _input_limit_a(self) -> float | None:
|
||||
"""Max input current allowed for the test environment (I limit
|
||||
field). None when the field does not parse (gate inactive)."""
|
||||
try:
|
||||
val = float(self._sup_current.get())
|
||||
return float(self._svi_ilimit.get())
|
||||
except ValueError:
|
||||
return
|
||||
if val > PSU_MAX_CURRENT_A:
|
||||
self._console(
|
||||
f"Supply I {val:g}A clamped to PSU max "
|
||||
f"{PSU_MAX_CURRENT_A:g}A", "warn")
|
||||
self._sup_current.delete(0, tk.END)
|
||||
self._sup_current.insert(0, f"{PSU_MAX_CURRENT_A:g}")
|
||||
return None
|
||||
|
||||
def _apply_supply(self) -> None:
|
||||
self._clamp_supply_current_entry()
|
||||
try:
|
||||
v = float(self._sup_voltage.get())
|
||||
i = float(self._sup_current.get())
|
||||
@@ -1490,18 +1485,20 @@ class TestbenchGUI(tk.Tk):
|
||||
self._load_value.config(foreground="red")
|
||||
self.after(1000, lambda: self._load_value.config(foreground=""))
|
||||
return
|
||||
# PSU capability gate (CC/CP; live readings when available)
|
||||
if mode in ("CC", "CP"):
|
||||
# Input-current gate (CC/CP; live readings when available), against
|
||||
# the user-set I limit for this test environment
|
||||
imax = self._input_limit_a()
|
||||
if mode in ("CC", "CP") and imax is not None:
|
||||
vin = self._latest_data.get("supply_V", 0.0)
|
||||
vout = self._latest_data.get("load_V", 0.0)
|
||||
if vout < 5.0:
|
||||
vout = VOUT_NOM_V
|
||||
if vin > 5.0:
|
||||
iin_est = _est_input_current(mode, val, vin, vout)
|
||||
if iin_est > PSU_MAX_CURRENT_A:
|
||||
if iin_est > imax:
|
||||
self._console(
|
||||
f"Load {mode}={val:g} rejected: est. input current "
|
||||
f"{iin_est:.1f}A > PSU max {PSU_MAX_CURRENT_A:g}A "
|
||||
f"{iin_est:.1f}A > I limit {imax:g}A "
|
||||
f"at Vin={vin:.1f}V / Vout={vout:.1f}V", "error")
|
||||
self._load_value.config(foreground="red")
|
||||
self.after(1000, lambda: self._load_value.config(foreground=""))
|
||||
@@ -1650,14 +1647,6 @@ class TestbenchGUI(tk.Tk):
|
||||
messagebox.showerror("Invalid Input", "Check sweep parameters.")
|
||||
return
|
||||
|
||||
if params["current_limit"] > PSU_MAX_CURRENT_A:
|
||||
self._console(
|
||||
f"I limit {params['current_limit']:g}A clamped to PSU max "
|
||||
f"{PSU_MAX_CURRENT_A:g}A", "warn")
|
||||
params["current_limit"] = PSU_MAX_CURRENT_A
|
||||
self._svi_ilimit.delete(0, tk.END)
|
||||
self._svi_ilimit.insert(0, f"{PSU_MAX_CURRENT_A:g}")
|
||||
|
||||
# Ask for output file
|
||||
default_name = time.strftime("sweep_vi_%Y%m%d_%H%M%S.csv")
|
||||
path = filedialog.asksaveasfilename(
|
||||
@@ -1808,9 +1797,10 @@ class TestbenchGUI(tk.Tk):
|
||||
"STM32 not linked - thermal pause guard inactive for this "
|
||||
"sweep", "warn")
|
||||
|
||||
# PSU capability gate: never command an operating point whose
|
||||
# estimated input draw exceeds what the supply can source.
|
||||
psu_imax = min(current_limit, PSU_MAX_CURRENT_A)
|
||||
# Input-current gate: the I limit field IS the maximum input current
|
||||
# allowed for this test environment -- never command an operating
|
||||
# point whose estimated input draw exceeds it.
|
||||
psu_imax = current_limit
|
||||
vout_est = VOUT_NOM_V # refined from measured load voltage as we go
|
||||
first_v = v_start if v_step > 0 else max(v_start, v_stop)
|
||||
if _est_input_current(load_mode, l_start, first_v, vout_est) > psu_imax:
|
||||
@@ -1967,8 +1957,8 @@ class TestbenchGUI(tk.Tk):
|
||||
ll += l_step
|
||||
if rejected:
|
||||
self._console(
|
||||
f"V={v:.1f}V: rejected {rejected} step(s) - PSU "
|
||||
f"input limit {psu_imax:g}A / load range", "warn")
|
||||
f"V={v:.1f}V: rejected {rejected} step(s) - input "
|
||||
f"limit {psu_imax:g}A / load range", "warn")
|
||||
v += v_step
|
||||
finally:
|
||||
# Ramp load down gradually to avoid sudden transients
|
||||
|
||||
Reference in New Issue
Block a user