janikandClaude Fable 5 f709d634e8 bench-plot: per-file Vin-bin checkbox picker for combining runs
Combining multiple CSVs pooled everything blindly; when two runs cover
the same Vin bin the user now gets a checkbox grid (row per Vin bin,
column per file, counts per cell, overlapping bins highlighted) to
decide per bin which file contributes. Opens automatically on overlap;
--pick forces it (also useful to cut bad columns from a single file),
--no-pick suppresses it for scripted use.

Also: picker/file-dialog windows force themselves to the foreground
(spawned from the GUI button, Windows opened them hidden behind the
GUI); unreadable or still-being-written (empty) CSVs are skipped with a
note instead of killing the run; fatal errors show a messagebox since
stderr is invisible when launched from the GUI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 16:59:34 +07:00

MPPT Testbench

Unified tool for testing and tuning MPPT (Maximum Power Point Tracking) converters. Combines three bench instruments with direct STM32 firmware access for closed-loop parameter optimization.

Instrument Role Interface
ITECH IT6537D DC power supply (solar panel simulator, 80V/120A/6kW) USB-TMC / SCPI via PyVISA
Prodigit 3366G DC electronic load (600V/420A/6kW) RS-232 (115200 8N1 RTS/CTS)
HIOKI 3193-10 Power analyzer (efficiency measurement) GPIB via UsbGpib / PyVISA
STM32G474 Converter firmware (LVSolarBuck64) Serial 460800 baud (debug protocol)

Wiring

                        +------------------+
  IT6500D  --(+/-)-->   |   MPPT Tracker   |  --(+/-)-->  Prodigit 3366G
                        |      (DUT)       |
  HIOKI Ch5 --(sense)-- |  Input    Output | --(sense)--  HIOKI Ch6
                        +------------------+
                              |
                          STM32 debug
                          serial (COM4)

  HIOKI EFF1 = P6 / P5 x 100%  (output power / input power)

Installation

Requires Python 3.12+, NI-VISA runtime, and uv.

git clone --recurse-submodules https://git.b4l.co.th/B4L/mppt-testbench.git
cd mppt-testbench
uv sync

The debug console (inside code64/) has its own environment:

cd code64
uv sync

Step-by-Step Guide

1. Connect and verify instruments

# Check all bench instruments respond
uv run bench identify

# Check STM32 responds (reads params + telemetry)
uv run bench stm32-read --stm32-port COM4

2. Configure instruments for MPPT testing

uv run bench setup

This sets wiring mode (1P2W), DC coupling, auto-ranging, efficiency formula (EFF1 = P6/P5), and display layout on the HIOKI.

3. Basic measurements

# Single reading from all instruments
uv run bench measure

# Continuous text monitoring with CSV export
uv run bench monitor --interval 1.0 --output data.csv

4. Launch the GUI

uv run bench-gui

The GUI provides:

  • Real-time readouts from all three instruments
  • Supply voltage/current control with ON/OFF indicators
  • Load mode (CC/CR/CV/CP) and setpoint control
  • HIOKI channel range selectors + degauss buttons
  • Meter format selector (scientific/normal)
  • 2D sweep panel with time estimate
  • Live-updating power, efficiency, voltage, and current plots plus STM32 Vfly and vfly_correction/vfly_ofs_applied plots (selectable) — all graphs show the last 20 seconds
  • STM32 telemetry panel ("Link STM32", COM4 @ 460800 8-O-1): every field of the 100 Hz broadcast (V/I/P + net efficiency, temps, Vfly group, control mode, HRTIM compare registers, status flags, fault registers, param echo), with Ping and Clear Flags buttons; auto-reconnects on serial errors
  • Data logging: instrument rows (with the latest STM32 snapshot merged in as stm_* columns) to the chosen CSV, plus the full-rate 100 Hz telemetry stream to <name>_telem.csv alongside. Logging is ON by default: every launch auto-starts a log at logs/data_<timestamp>.csv (relative to the working directory); use Stop Log / Start Log to switch to a custom path
  • Console log panel (STM32 fault flags are reported here as they latch)
  • Input-current guard: the sweep "I limit" field is the maximum input current allowed for the test environment (set it to whatever the PSU on the bench can source; defaults to 20 A, no hardcoded ceiling). It is programmed as the supply CC limit, and sweep steps whose estimated input draw I_in = P_out / (0.90 * V_in) exceeds it are rejected (skipped and reported per voltage), regardless of the requested step range; a measured backstop additionally drops any point where the supply actually exceeded the limit and backs the load off. Manual CC/CP load setpoints are checked against the same limit using live Vin/Vout readings.
  • Supply-trip protection: before each voltage step the load is released back to I start first, so a heavy load release never lands mid-ramp (that overshoots the setpoint -- a 46 A release ramping to 80 V peaked at 80.46 V and tripped the supply OVP). At sweep start the supply's programmed OVP level is checked against the sweep maximum (abort under 2 V margin, warn under 5 V). If the supply reads ~0 V mid-sweep (a protection shut the output down), the sweep aborts immediately, reports which protection fired (OVP / OV / OC / OP / OT), and saves the points collected so far instead of logging garbage rows for the rest of the grid.
  • Load range pinning: a mid-sweep auto-range transition on the Prodigit momentarily unloads the converter, so at sweep start the CC range is pinned to Range II for the whole run (auto-ranging restored after, with the load off). The reachable maximum of the selected range is verified empirically -- the sweep max is programmed with the load off and read back; if the readback comes back clamped, steps above it are rejected instead of silently clamped, and a sweep that fits nothing aborts up front.
  • Thermal sweep guard (needs the STM32 link): before every sweep step the heatsink/board temperatures are checked against the firmware trip limits (60 C / 80 C). At 57 C / 77 C the sweep pauses, holds the load at 1 A (CC; ~1 A worth of W in CP), and waits until both temps drop 5 C below the pause thresholds, then resumes at the same step -- no points are lost. If the STM32 link is down the sweep still runs, with a console warning that the guard is inactive.

5. Run efficiency sweeps

Voltage sweep (1D)

uv run bench sweep \
  --v-start 30 --v-stop 100 --v-step 5 \
  --current-limit 20 \
  --load-mode CP --load-value 200 \
  --settle 2.0 -o voltage_sweep.csv

Load sweep at fixed voltage (1D)

uv run bench sweep-load \
  --voltage 60 --current-limit 20 \
  --i-start 0.5 --i-stop 15 --i-step 0.5 \
  --settle 2.0 -o load_sweep.csv

2D voltage x load sweep (efficiency map)

# Constant Power mode
uv run bench sweep-vi \
  --v-start 60 --v-stop 100 --v-step 5 \
  --l-start 50 --l-stop 500 --l-step 50 \
  --load-mode CP --current-limit 20 \
  --settle 2.0 -o map_cp.csv

# Constant Current mode
uv run bench sweep-vi \
  --v-start 35 --v-stop 100 --v-step 5 \
  --l-start 0.5 --l-stop 15 --l-step 0.5 \
  --load-mode CC --current-limit 20 \
  --settle 2.0 -o map_cc.csv

6. Analyze sweep results

# Generate efficiency overlay, heatmap, and power loss plots (no instruments needed)
uv run bench plot-sweep map_cp.csv

# Save plots without displaying
uv run bench plot-sweep map_cp.csv --no-show -o plots/

Produces three PNG files:

  • *_efficiency.png -- efficiency vs load, one line per voltage, best point marked
  • *_heatmap.png -- 2D efficiency surface (voltage x load)
  • *_loss.png -- power loss vs load, all voltages overlaid

Efficiency vs Vin vs current from any logged CSV

bench-plot auto-detects all three CSV formats the tooling produces -- sweep CSVs, GUI data logs (data_*.csv), and full-rate telemetry logs (*_telem.csv) -- and draws an operating-point map (x = Vin, y = current, color = efficiency) plus efficiency-vs-current curves grouped by Vin bin:

uv run bench-plot                    # no args -> file-picker dialog
uv run bench-plot data_20260703_140000.csv
uv run bench-plot run1_telem.csv run2_telem.csv --vin-bin 2 --save eff.png

# options: --current iout|iin, --source auto|hioki|instr|stm (data logs),
#          --min-pout W (default 5), --vin-bin V (default 1), --save PNG,
#          --pick / --no-pick (per-file Vin-bin checkbox picker)

Multiple files are pooled into one dataset. When two files cover the same Vin bin, a checkbox picker opens automatically -- one row per Vin bin, one column per file, cell numbers showing points per bin, overlapping bins highlighted -- so you decide per bin which file's data to use (e.g. keep the re-measured 72 V column from the new run, the rest from the old one). --pick forces the picker even without overlap (useful to cut bad columns from a single file); --no-pick skips it for scripted/batch use.

Also reachable via the GUI's "Plot Eff..." button (Logging section, opens the same dialog preselecting the last log) and plot_eff.bat one level up (double-click for the dialog, or drag && drop CSV files onto it).

For GUI data logs the efficiency source defaults to auto: HIOKI EFF1 if the meter was connected, else supply/load power ratio, else the board's own stm_eff_net_pct. Telemetry logs always use the board's net efficiency ((P_out - P_sys) / P_in, iout_slow). Points below --min-pout (default 5 W, same as the GUI display gate) are dropped.

7. Tune converter parameters

The tuning commands combine the testbench instruments (ground truth efficiency from HIOKI) with direct STM32 parameter writes to find optimal settings.

Read current STM32 state

uv run bench stm32-read

Write a single parameter

uv run bench stm32-write --param dt_10_20A --value 20

Sweep a parameter to find the optimum

Sweeps a parameter from start to stop, measuring HIOKI efficiency + STM32 telemetry at each step. Plots the result.

# Optimize deadtime for the 10-20A bracket at 300W
uv run bench tune-param \
  --param dt_10_20A --start 14 --stop 40 --step 1 \
  --voltage 60 --current-limit 20 \
  --load-mode CP --load-value 300 \
  --settle 3.0 -o dt_tune.csv

# Tune Vfly proportional gain
uv run bench tune-param \
  --param vfly_kp --start -2 --stop 2 --step 0.1 \
  --voltage 60 --current-limit 20 \
  --load-mode CP --load-value 200 \
  --settle 3.0

Optimize the global dead-time

The firmware uses a single global dead-time (dt_normal). tune-deadtime sweeps it from --dt-start to --dt-stop, optionally at several --load-values, and picks the highest-efficiency value.

# Sweep at a single load and report the best value
uv run bench tune-deadtime \
  --voltage 60 --current-limit 20 --load-mode CP \
  --dt-start 14 --dt-stop 50 --dt-step 1 \
  -o deadtime_results.csv

# Sweep across several loads, then apply the best dt_normal to the STM32
uv run bench tune-deadtime \
  --voltage 60 --current-limit 20 --load-mode CP \
  --load-values 100,300,500 \
  --apply

8. Shade / irradiance profile simulation

Simulate cloud passing or partial shading with a CSV-driven sequence:

uv run bench shade-profile \
  --profile samples/cloud_pass.csv \
  --settle 2.0 -o shade_results.csv

Profile CSV format: time,voltage,current_limit,load_mode,load_value

9. Real-time debug console (TUI)

For live monitoring and parameter tuning via the Textual terminal UI:

cd code64
uv run debug-console COM4

Keybindings: p ping, f toggle EMA filter, s shutoff, x reset, t 50% duty test, c relay on, d relay off, h hold converter, g toggle precharge, q quit. Parameter writes are auto-retried until ACKed (the MCU's RX is EMI-lossy while switching).

10. Direct instrument control

# Supply
uv run bench supply set --voltage 48 --current 10
uv run bench supply on
uv run bench supply off

# Load
uv run bench load set --mode CP --value 200
uv run bench load on
uv run bench load off

# Emergency shutdown (load first, then supply)
uv run bench safe-off

CLI Reference

uv run bench [-h] [--supply-address ADDR] [--load-port PORT] [--load-baud BAUD]
            [--meter-address ADDR] [--timeout MS]
            [--stm32-port PORT] [--stm32-baud BAUD]
            {command}
Command Description
identify Show identity and status of all instruments
setup Configure all instruments for MPPT testing
measure Single measurement from all three instruments
monitor Continuous text monitoring with optional CSV
live Real-time 4-panel matplotlib graph
sweep Voltage sweep with efficiency recording
sweep-load Load current sweep at fixed voltage
sweep-vi 2D voltage x load sweep (efficiency map)
efficiency Averaged efficiency at a fixed operating point
shade-profile Run shade/irradiance profile from CSV
plot-sweep Generate analysis plots from sweep CSV (offline)
stm32-read Read all STM32 parameters and telemetry
stm32-write Write a parameter to the STM32
tune-param Sweep an STM32 parameter while measuring efficiency
tune-deadtime Auto-optimize deadtime for each current bracket
supply Direct IT6500D control (on/off/set)
load Direct Prodigit 3366G control (on/off/set)
safe-off Emergency shutdown (load first, then supply)

Global Options

Option Default Description
--supply-address auto-detect IT6500D VISA address
--load-port COM11 Prodigit 3366G serial port
--load-baud 115200 Prodigit 3366G baud rate
--meter-address auto-detect HIOKI 3193-10 VISA address
--timeout 5000 VISA timeout in milliseconds
--stm32-port COM4 STM32 debug serial port
--stm32-baud 460800 STM32 debug baud rate

Tunable STM32 Parameters

Names, IDs, types and ranges mirror the firmware (code64/debug_console/protocol.py).

Parameter Type Range Description
VREF uint16 2340-3500 ADC reference voltage
vfly_kp float -10 to 10 Vfly proportional gain (mode 1, duty asymmetry)
vfly_ki float -10 to 10 Vfly integral gain (mode 1)
vfly_kp_phase float -10 to 10 Vfly P gain (mode 2, master-phase offset)
vfly_phase_clamp uint16 0-10000 Clamp on the master-phase offset (mode 2)
vfly_clamp uint16 0-10000 Vfly integrator clamp (mode 1)
vfly_loop_trig uint16 1-10000 Vfly loop counter trigger
vfly_active uint8 0-3 Vfly mode: 0 off, 1 duty-asym PI, 2 phase P, 3 manual both
test_corr int16 -3000 to 3000 Manual duty-asymmetry correction (mode 3)
phase_ofs int16 -3000 to 3000 Master-phase offset: manual (mode 3), readback (mode 2)
cc_target float 0-60000 CC target (mA)
cc_gain float -1 to 1 CC proportional gain
cc_min_step / cc_max_step float -1000-0 / 0-1000 CC step clamps
cc_loop_trig uint16 1-10000 CC loop counter trigger
cc_active int32 0-1 CC loop enable
mppt_step float 1-200 MPPT P&O step size
mppt_duty_min / mppt_duty_max float 0-6800 MPPT duty search bounds (CMP ticks)
mppt_loop_trig uint16 1-50000 MPPT loop counter trigger
mppt_active int32 0-1 MPPT loop enable
cv_threshold / cv_hysteresis float 20000-30000 / 0-5000 CV corner (mV)
cc_threshold / cc_hysteresis float 0-55000 / 0-10000 CC/Iout limit (mA)
dt_normal uint16 14-200 Single global dead-time (dt register ticks)
override_duty uint16 716-6442 Manual fixed-duty base (CMP ticks, D=10..90%)
manual_duty_en uint8 0-1 Enter manual fixed-duty mode
precharge_kp / precharge_ki float 0-100 / 0-10 Closed-loop precharge PI gains
precharge_reg_en uint8 0-1 Enable closed-loop precharge
dither_en uint8 0-1 Enable duty dithering (de-stack-band avoidance)
dither_band_lo / dither_band_hi uint16 716-6442 Forbidden duty band edges (CMP ticks)
dither_anear / dither_afar uint16 716-6442 Out-of-band dither anchors
dither_dzero uint16 716-6442 |e| fold center (D=0.5)
adc4_trig_phase uint16 3-14313 HRTIM master CMP3: iout_slow sample instant
iin_zero_sum uint16 0-32760 IIN software zero offset (sum-of-8 counts)

CSV Output Format

Sweep CSV files contain:

Column Description
voltage_set Supply voltage setpoint (V)
current_limit Supply current limit (A)
load_setpoint Load setpoint value (A for CC, W for CP)
supply_V/I/P Supply measured voltage, current, power
load_V/I/P Load measured voltage, current, power
input_power HIOKI P5 -- power into MPPT tracker (W)
output_power HIOKI P6 -- power out of MPPT tracker (W)
efficiency HIOKI EFF1 -- P6/P5 x 100 (%)

Tuning CSV files additionally contain param_name, param_value, and STM32 telemetry columns (stm_vin, stm_vout, stm_iin, stm_iout, stm_eff, stm_vfly, stm_etemp).

GUI data-log CSVs contain the instrument columns plus the latest STM32 broadcast snapshot per row (stm_counterstm_age_s; flag/fault registers as hex). While logging, the full-rate 100 Hz telemetry stream is additionally written to <name>_telem.csv with every broadcast field (one row per fresh publish, pc_time/t_mono timestamps, computed p_in_W/p_out_W).

Note: STM32-derived power_out_W/efficiency now use iout_slow (the PWM-synchronous ADC4 output current) instead of the fast protection-path iout — tuner numbers shift slightly vs. old logs.

Project Structure

mppt-testbench/
+-- IT6500D/              git submodule -- DC power supply driver
+-- PRODIGIT-3366G/       git submodule -- electronic load driver
+-- HIOKI-3193-10/        git submodule -- power analyzer driver
+-- testbench/
|   +-- __init__.py       exports MPPTTestbench
|   +-- bench.py          orchestrator (sweeps, measurement, auto-range wait)
|   +-- cli.py            unified CLI entry point
|   +-- gui.py            tkinter GUI with live plots
|   +-- gui_workers.py    background instrument I/O thread
|   +-- stm32_link.py     STM32 debug protocol: 114B broadcast RX + CRC-framed TX commands (8-O-1)
|   +-- plot_eff.py       efficiency vs Vin vs current plots from any logged CSV
|   +-- tuner.py          automated tuning routines (param sweep, deadtime opt)
+-- code64/
|   +-- Core/             STM32G474 firmware (C)
|   +-- Drivers/          HAL drivers
|   +-- debug_console/    Textual TUI for live debugging
|   +-- pyproject.toml    uv-compatible package config
+-- samples/              shade profile CSV examples
+-- pyproject.toml        package config, entry points: bench, bench-gui, bench-plot

Dependencies

S
Description
No description provided
Readme
1.8 MiB
Languages
C 96.5%
Python 3.2%
Assembly 0.2%
Linker Script 0.1%