Add shade profiles, 2D V×I sweep, meter format toggle, ON/OFF indicators, and GUI console
- Shade profile: CSV-driven irradiance/voltage sequences with load control (bench.run_shade_profile, CLI shade-profile command, GUI profile panel) - 2D sweep: voltage × load current efficiency map with live graph updates (bench.sweep_vi, CLI sweep-vi command, GUI sweep panel with background thread) - GUI: meter format selector (scientific/normal), supply/load ON/OFF indicators, console log with stdout redirect and color-coded messages - Sample profiles: cloud_pass, partial_shade, intermittent_clouds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -438,6 +438,55 @@ def cmd_efficiency(bench: MPPTTestbench, args: argparse.Namespace) -> None:
|
||||
print(f"Average efficiency: {result['avg_efficiency']:.2f} %")
|
||||
|
||||
|
||||
def cmd_sweep_vi(bench: MPPTTestbench, args: argparse.Namespace) -> None:
|
||||
"""Run a 2D voltage × load current sweep."""
|
||||
print(
|
||||
f"2D sweep: V={args.v_start:.1f}-{args.v_stop:.1f}V (step {args.v_step:.1f}), "
|
||||
f"I_load={args.i_start:.2f}-{args.i_stop:.2f}A (step {args.i_step:.2f}), "
|
||||
f"I_limit={args.current_limit:.1f}A, settle={args.settle:.1f}s"
|
||||
)
|
||||
print()
|
||||
|
||||
results = bench.sweep_vi(
|
||||
v_start=args.v_start,
|
||||
v_stop=args.v_stop,
|
||||
v_step=args.v_step,
|
||||
i_start=args.i_start,
|
||||
i_stop=args.i_stop,
|
||||
i_step=args.i_step,
|
||||
current_limit=args.current_limit,
|
||||
settle_time=args.settle,
|
||||
)
|
||||
|
||||
_write_sweep_csv(results, args.output)
|
||||
_print_sweep_summary(results)
|
||||
|
||||
|
||||
def cmd_shade_profile(bench: MPPTTestbench, args: argparse.Namespace) -> None:
|
||||
"""Run a shade / irradiance profile from a CSV file."""
|
||||
steps = MPPTTestbench.load_shade_profile(args.profile)
|
||||
duration = steps[-1]["time"] if steps else 0
|
||||
|
||||
print(f"Shade profile: {args.profile}")
|
||||
print(f" {len(steps)} steps over {duration:.0f}s, settle={args.settle:.1f}s")
|
||||
|
||||
# Show what modes/values are used
|
||||
modes = {s.get("load_mode", "?") for s in steps}
|
||||
voltages = [s["voltage"] for s in steps]
|
||||
currents = [s["current_limit"] for s in steps]
|
||||
print(
|
||||
f" Voltage: {min(voltages):.1f} - {max(voltages):.1f}V, "
|
||||
f"I_limit: {min(currents):.1f} - {max(currents):.1f}A, "
|
||||
f"Load modes: {', '.join(sorted(modes))}"
|
||||
)
|
||||
print()
|
||||
|
||||
results = bench.run_shade_profile(steps, settle_time=args.settle)
|
||||
|
||||
_write_sweep_csv(results, args.output)
|
||||
_print_sweep_summary(results)
|
||||
|
||||
|
||||
def cmd_supply(bench: MPPTTestbench, args: argparse.Namespace) -> None:
|
||||
"""Control the DC supply directly."""
|
||||
if args.action == "on":
|
||||
@@ -515,6 +564,8 @@ examples:
|
||||
%(prog)s sweep --v-start 10 --v-stop 50 --v-step 1 --current-limit 10 -o sweep.csv
|
||||
%(prog)s sweep-load --voltage 75 --current-limit 10 --i-start 1 --i-stop 20 --i-step 1 -o load.csv
|
||||
%(prog)s efficiency --voltage 36 --current-limit 10 --samples 10
|
||||
%(prog)s sweep-vi --v-start 35 --v-stop 100 --v-step 5 --i-start 0.5 --i-stop 30 --i-step 1 --current-limit 35 -o map.csv
|
||||
%(prog)s shade-profile --profile cloud_pass.csv --settle 2.0 -o shade_results.csv
|
||||
%(prog)s supply set --voltage 24 --current 10
|
||||
%(prog)s supply on
|
||||
%(prog)s load set --mode CC --value 5.0
|
||||
@@ -599,6 +650,24 @@ examples:
|
||||
p_eff.add_argument("--load-mode", choices=["CC", "CR", "CV", "CP"])
|
||||
p_eff.add_argument("--load-value", type=float)
|
||||
|
||||
# sweep-vi (2D)
|
||||
p_svi = sub.add_parser("sweep-vi", help="2D voltage × load current sweep (efficiency map)")
|
||||
p_svi.add_argument("--v-start", type=float, required=True, help="Start voltage (V)")
|
||||
p_svi.add_argument("--v-stop", type=float, required=True, help="Stop voltage (V)")
|
||||
p_svi.add_argument("--v-step", type=float, required=True, help="Voltage step (V)")
|
||||
p_svi.add_argument("--i-start", type=float, required=True, help="Start load current (A)")
|
||||
p_svi.add_argument("--i-stop", type=float, required=True, help="Stop load current (A)")
|
||||
p_svi.add_argument("--i-step", type=float, required=True, help="Current step (A)")
|
||||
p_svi.add_argument("--current-limit", type=float, required=True, help="Supply current limit (A)")
|
||||
p_svi.add_argument("--settle", type=float, default=2.0, help="Settle time per step (s)")
|
||||
p_svi.add_argument("-o", "--output", help="CSV output file")
|
||||
|
||||
# shade-profile
|
||||
p_shade = sub.add_parser("shade-profile", help="Run a shade/irradiance profile from CSV")
|
||||
p_shade.add_argument("--profile", required=True, help="Profile CSV file (time,voltage,current_limit,...)")
|
||||
p_shade.add_argument("--settle", type=float, default=2.0, help="Settle time per step (s)")
|
||||
p_shade.add_argument("-o", "--output", help="CSV output file for results")
|
||||
|
||||
# supply (direct control)
|
||||
p_sup = sub.add_parser("supply", help="Direct supply control")
|
||||
p_sup_sub = p_sup.add_subparsers(dest="action", required=True)
|
||||
@@ -631,6 +700,8 @@ examples:
|
||||
"sweep": cmd_sweep,
|
||||
"sweep-load": cmd_sweep_load,
|
||||
"efficiency": cmd_efficiency,
|
||||
"sweep-vi": cmd_sweep_vi,
|
||||
"shade-profile": cmd_shade_profile,
|
||||
"supply": cmd_supply,
|
||||
"load": cmd_load,
|
||||
"safe-off": cmd_safe_off,
|
||||
|
||||
Reference in New Issue
Block a user