Solid-state battery,
driven by Claude Code.
A composite PEO/LLZO + NMC622 solid-state ERS pack, modelled in MATLAB/Simulink R2023a against a current profile rebuilt from the 2026 Miami GP race winner's fastest lap — fetched with FastF1, mapped throttle-to-deploy and brake-to-regen, and dispatched into the live model end-to-end through MCP tool calls. Plots and reports are produced without leaving the AI loop.
One MCP loop, two engines, one race lap.
The integration is deliberately small: Claude Code orchestrates the work, FastF1 fetches the race telemetry, the MATLAB MCP server hands the current profile to a live R2023a session, and the Simulink model — built earlier in this same project by the agent through dozens of HIL-driven iterations — produces the plots and the auto-generated PDF report. There is no GUI step. The model file, the parameter file, the test suite, the report script and the captured screenshots in this page were all produced by tool calls from inside Claude Code.
CLAUDE CODE · MCP · MATLAB INTEGRATION
Telemetry · current · physics · pack · run.
Each step is one logical hand-off. Every artefact below — Python script, CSV, MATLAB run script, plot, MAT file — is committed to the project repo so the next iteration starts from a known state.
FastF1 → race-winner's fastest lap
The Python script connects to FastF1 3.8.1, loads the 2026 Miami GP race session, picks the winner from session.results, and pulls the fastest lap car-data via pick_drivers().pick_fastest().get_car_data(). The first run of the season triggers a cold cache fill against the F1 timing API — every run after that hits the local ~/fastf1_cache, so iteration is instant.
The car-data trace for the winner's fastest race lap contains 328 samples covering 91.76 s, with speed ranging 65–327 km/h, throttle on for 63.8 % of the lap and brake active 16.5 % of the lap. The fastest race lap landed at 1:31.968 on lap 34.
lap_metadata.json next to the CSV — every plot in this page can be traced back to one record.git clean.Throttle & brake → ERS deploy & regen
Real F1 ERS is governed by the engine map and the driver's MGU-K request, but for this study a deliberately simple, physics-defensible mapping is enough: throttle percentage drives the pack discharge current and braking events trigger regen charge, both clipped to the BMS-defined ±410 A pack limits. When brake is on, throttle contribution is zeroed defensively.
For the Miami winner's lap that produces a current trace with mean +192 A, RMS 353 A, peaks at -410 A on hard braking and +410 A on full-throttle pulls. The single-lap input profile is the file the Simulink model consumes verbatim — profile_miami_gp_2026.csv ships in the project's Test cycles/ folder alongside the other canonical bench cycles.
// scripts/fetch_miami_gp_2026.py — race-winner fastest lap session = fastf1.get_session(2026, "Miami", "R") session.load(telemetry=True, laps=True) winner = session.results.iloc[0] # Race winner fastest = session.laps.pick_drivers(winner["Abbreviation"]).pick_fastest() car = fastest.get_car_data().add_distance() # 328 samples · 91.76 s · 65–327 km/h # Throttle (0..100) → ERS discharge current # Brake (bool) → ERS regen current discharge = (car["Throttle"] / 100) * I_MAX_DISCHARGE regen = -car["Brake"].astype(float) * I_MAX_REGEN discharge = np.where(car["Brake"], 0.0, discharge) current_A = np.clip(discharge + regen, -410, +410)
Electro-thermal cell — composite PEO/LLZO + NMC622
Each cell in the pack is the same MATLAB Function block — ssb_cell_model_fcn — coupled to a thermal sub-block. The internal resistance follows an Arrhenius temperature law with literature-anchored reference resistance and activation energy, the OCV is a literature lookup against state of charge, the entropy coefficient drives reversible heating, and a single RC pair captures diffusion dynamics. Heat from I²R losses and the entropy term feeds into a thermal node with cell mass, specific heat and convection to the dielectric oil.
The chemistry choice — composite PEO/LLZO solid electrolyte with single-ion copolymers, an ultra-thin membrane and a power-optimised multi-stack pouch design — is what makes the headline pack numbers possible. The composite drops the activation energy for ionic conductivity well below neat amorphous PEO, and tabless current collectors plus a LiF/LLZO interface buffer take the cell-level resistance down to a small fraction of what a conventional PEO build would deliver. None of that came from speculation — every parameter has a literature anchor.
CELL ELECTRO-THERMAL FEEDBACK · ARRHENIUS-COUPLED IMPEDANCE
Pack, oil-immersion cooling, governed pack
Cells are assembled in series into an 850 V / 2.17 kWh pack. Cooling is dielectric-oil immersion: each cell sees a convective heat-transfer coefficient against a lumped coolant mass, with a variable-speed pump throttled by a temperature-aware control law that keeps the pack inside the PEO operating window.
The BMS sits between the requested current and the pack. Protection thresholds are V_cell ∈ [2.50, 4.25] V and T_cell ∈ [40, 80] °C; a Derating_Logic block derates allowable charge/discharge current as the cell approaches voltage or thermal limits; an EKF estimates SOC from cell voltage + current; an Ah-counter cross-checks. A 5 kW PTC pre-heater wakes when the pack is below 55 °C and shuts off at 65 °C — necessary because PEO conductivity collapses below 60 °C.
m·Cp·dT/dt = Q_gen − Q_out integrated by ode23t. Replaced an earlier Memory-block formulation that produced visually plausible but incorrect temperature traces.I_max_chg and I_max_dis as functions of cell voltage and temperature; enforces them via the PowerLimiter block before they reach the cell array.Live MATLAB session, single MCP tool call
The MATLAB MCP server attaches to a running R2023a session — same session the engineer would use interactively — so every cd, load_system, set_param and sim happens in the same workspace, with the same paths, the same warnings, the same output. Claude Code dispatches one evaluate_matlab_code tool call that runs scripts/run_f1_miami_gp_2026.m; the script loads the master parameter file, builds I_profile in the base workspace, kills EnablePacing (golden rule — pacing forces real-time playback and would make sweeps unusable), runs the simulation, extracts logged signals, computes headline metrics, exports three PNGs through exportgraphics and saves a MAT file for the page.
Wall-time for the 91.76 s lap is 4.69 s — about 20× real-time on this laptop. That is the figure that makes parameter sweeps tractable: a 5-point sweep over electrolyte thickness, cathode area or pack series count finishes in roughly the same wall time as one cycle ran in real life.
// Claude Code → MATLAB MCP → live R2023a session — single tool call mcp__matlab__evaluate_matlab_code({ "code": "cd('Solid state battery first apprach'); run('scripts/run_f1_miami_gp_2026.m');", "project_path": "C:/Users/santi/Desktop/Solid state battery first apprach" }) // → returns command-window output verbatim, including warnings, simOut, plot exports // → writes docs/F1_Miami_GP_2026_results.mat + three PNG plots to docs/ // → no manual MATLAB clicks anywhere in the loop
% scripts/run_f1_miami_gp_2026.m — dispatched by Claude Code via MCP cd(projDir); addpath(fullfile(projDir, 'scripts')); run('params/ssb_params.m'); % chemistry + pack parameters modelName = 'SSB_Model'; load_system(fullfile(projDir, 'models', modelName)); set_param(modelName, 'EnablePacing', 'off'); % golden rule: never pace a sweep data = readmatrix('Test cycles/F1_Miami_GP_2026/profile_miami_gp_2026.csv'); I_profile = timeseries(data(:,2), data(:,1)); % base-workspace handoff set_param(modelName, 'StopTime', num2str(data(end,1))); simOut = sim(modelName); % ode23t · 4.69 s wall · 91.76 s sim V_pack = simOut.get('V_pack'); I_pack = simOut.get('I_pack'); SOC = simOut.get('SOC_cells'); T_cool = simOut.get('T_coolant');
evaluate_matlab_code, run_matlab_file, check_matlab_code, detect_matlab_toolboxes as JSON-RPC tools. Returns the command-window output verbatim — warnings, sim progress, errors, all visible to the orchestrator.set_params it off before every run and asserts at startup; CLAUDE.md elevates the rule to a golden rule because the project has been bitten by it before.print resolution dance. Each plot in this page comes from a single exportgraphics(f, …, 'Resolution', 150) call.Built by Claude, refined in HIL.
The Simulink model was authored by Claude, complementing its own expertise with the engineer's domain knowledge and the public solid-state battery literature. Each subsystem — the cell electro-thermal physics, the CellArray assembly, the TMS oil-immersion loop, the BMS protection layer, the PowerLimiter and the Signal_Monitor — was assembled by the agent and cross-checked against published cell-chemistry data and the engineer's review, not authored block-by-block by hand.
The HIL sessions that followed were exclusively about refinement and fine-tuning: chasing temperature-readout artefacts to their root cause, replacing a Memory block with an Integrator where the thermal ODE needed continuous state, calibrating entropy-coefficient units, tightening the cooling-loop gains, walking through the BMS Derating_Logic block-by-block. The architecture came from a Claude + engineer + literature loop; the polish came from sustained engineer-in-the-loop review.
CELL STACK CROSS-SECTION · LI-METAL | COMPOSITE PEO/LLZO | NMC622
What 92 seconds of Miami does to the pack.
Peak deployed power lands at 350 kW — landing on the iter-5f design point. Coolant temperature peaks at 65.0 °C and stabilises in the 61–63 °C band over the lap, well inside the BMS over-temperature threshold. The auto-generated PDF report bundles every test-cycle plot, the cell + pack architecture diagrams, and the bug-history index into one document the engineer can hand to a colleague.
Every plot, every metric, every chart in the report was produced by the same MCP call that ran the simulation — no copy-paste, no spreadsheet hand-edit, no manual figure export.
The rules that shaped the architecture.
Every one of these is a hard rule the model and the orchestration layer have to respect. Most of them are scar tissue from a specific bug or a specific wasted iteration.
set_params it off before sim(); CLAUDE.md elevates the rule to a golden rule.params/ssb_params.m. AI agents may not modify chemistry or geometry without explicit approval — change one place or none.SSB_Model_iter<n>_backup.slx. The live model and the iter-5f backup are byte-identical at the current commit; older iterations are kept for diff and rollback.simOut, never from defaults.Bench numbers from a real lap.
All values below are from the single 2026 Miami GP race-winner-lap simulation.
Pack peak
Sim wall time
Coolant T peak
Race lap simulated
Every tool that touched the run.
Orchestration
- Claude Code CLI orchestrator
- MCP protocol Tool dispatch
- CLAUDE.md golden rules Per-project gates
- TaskCreate / TaskList Multi-step tracking
Telemetry
- FastF1 3.8.1 F1 timing API
- pandas Cleaning + resample
- numpy Throttle/brake map
- JSON sidecar Provenance
Simulation
- MATLAB R2023a Compute kernel
- Simulink R2023a Block diagram
- ode23t Stiff solver
- MATLAB MCP server Live-session bridge
Output
- exportgraphics PNG plots
- MATLAB Live Script Auto PDF report
- matlab.unittest Physics gate
- .mat sidecar Page assets
What the integration taught.
ode23t is fighting EnablePacing on a real-time clock. The golden rule in CLAUDE.md exists because the project was bitten by it before — the agent now refuses to start a run without checking the pacing flag.