Skip to content
Santiago Isaza.

F1 ERS Solid-State Battery Simulation · Solo Engineer · 2026

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.

PEO/LLZO
Solid electrolyte
850 V
Pack bus voltage
350 kW
Peak deployed power
20×
Real-time sim speed
Six-panel response of the SSB pack to the 2026 Miami GP race-winner's fastest lap — pack current, terminal voltage, power (peak 350 kW), average SOC, coolant temperature (peak 65 °C), and input-vs-simulated current overlay.
SIM OUTPUT · F1 MIAMI GP 2026 · 91.76 S LAP · 4.69 S WALL TIME

01 · System overview

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 · MCP · MATLAB FastF1 3.8.1 F1 telemetry API Public literature Cell chemistry params docs/*.png Captured plots PDF report Auto-generated Claude Code ORCHESTRATOR · MAX REASONING PER PROJECT CLAUDE.md GOLDEN RULES Python (FastF1 + pandas) scripts/fetch_miami_gp_2026.py throttle/brake → I_profile CSV handoff profile_miami_gp_2026.csv 328 samples · 91.76 s MATLAB MCP server mcp__matlab__evaluate_matlab_code attaches to live R2023a Simulink R2023a SSB_Model.slx · ode23t EnablePacing OFF CellArray ssb_cell_model_fcn R0(T), OCV, RC, dU/dT TMS Oil-immersion cooling loop PTC pre-heater for cold start BMS Protection · derating · EKF SOC ±410 A current limits PowerLimiter Voltage-aware clip Saturation guard Signal_Monitor tout, V_pack, I_pack SOC, T_coolant Every arrow is a tool call. No manual GUI step in the loop.

CLAUDE CODE · MCP · MATLAB INTEGRATION

02 · The five steps

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.

01
Telemetry fetch

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.

FastF1 3.8.1
Telemetry source
Single Python import, cached by event; gives Speed, Throttle, Brake, RPM, nGear, DRS, Distance from the official F1 timing feed.
pandas
Cleaning · resampling
Drops duplicate timestamps that would break ode23t ingestion, normalises the time axis to start at zero, persists the full raw frame for the page.
JSON metadata sidecar
Provenance
Race year, event, driver, lap number, lap time, sample count and current statistics get written to lap_metadata.json next to the CSV — every plot in this page can be traced back to one record.
Local cache folder
Cost control
First fetch ~30 s, every fetch after ~150 ms. Re-running the page is free. The cache lives outside the project tree so it survives git clean.
02
Current profile

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.

Cycle CSV current profile derived from the 2026 Miami GP race-winner's fastest lap — full-throttle ERS deploys at +410 A, hard-braking regen pulls at -410 A, both clipped to BMS limits over the 91.76 s lap.
INPUT · CYCLE CSV · 91.76 S · ±410 A CLIPPED
Throttle map
Discharge driver
Linear, zero-intercept map from raw throttle channel (0–100) to discharge current. Defensible because real F1 ERS pedal-to-deploy is monotonic and bounded.
Brake gate
Regen driver
Brake is boolean in F1 telemetry; when active, full-regen current is requested (-410 A) and any throttle-derived discharge is suppressed.
±410 A clip
Pack hard limit
Pre-clipping outside the model keeps the BMS PowerLimiter from doing it inside Simulink — clearer cause-and-effect when reading plots later.
Time-base normalisation
Solver hygiene
Subtract the lap-start offset, drop dupes, sort. ode23t will silently misbehave on a non-monotonic input timeseries — better to catch it at fetch time.
// 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)
03
Cell physics

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.

ELECTRO-THERMAL LOOP I_profile (t) From CSV ±410 A clipped Cell electro-thermal R0(T) · OCV(SOC) RC pair · dU/dT V_cell, V_pack Terminal voltage Q_gen = I²R + Q_rev Heat generation Thermal node m·Cp·dT/dt = Q_gen − Q_out CoolingLoop integrator T_cell to BMS + feedback Feedback: T modulates R0(T) — Arrhenius coupling

CELL ELECTRO-THERMAL FEEDBACK · ARRHENIUS-COUPLED IMPEDANCE

Cell internal resistance R0 vs temperature — Arrhenius curve with reference 0.25 mΩ at 65 °C, marked vertical line for T_ref.
R0(T) · ARRHENIUS · 20 KJ/MOL · ITER5F PARAMS
Arrhenius R0(T)
Resistance law
Single Arrhenius equation with reference R0 and activation energy from public literature; couples cell impedance to its own temperature so dispatch power changes as the cell heats.
OCV(SOC) lookup
Open-circuit term
Breakpoint table for NMC622 with cubic-spline interpolation; gives the no-load terminal voltage vs charge state.
Entropy coefficient dU/dT
Reversible heat
Per-SOC entropy lookup in mV/K — sign flips with current direction. Wrong units here is the historical #1 source of bugs in the model.
RC pair
Diffusion dynamics
Single-RC transient model with a short time constant — coarse but adequate for visualising the voltage dip behind a sudden load step.
04
Pack · TMS · BMS

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.

CoolingLoop integrator
Coolant mass thermal ODE
Lumped 3.5 kg oil mass with 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.
PTC pre-heater
Cold-start strategy
Resistive pre-heater wakes when the pack is below the lower temperature band and shuts off once the PEO operating window is reached. Necessary because PEO conductivity collapses outside that window and the pack would refuse to deploy power until the electrolyte is in range.
Derating_Logic
Current-limit envelope
Computes 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.
EKF SOC estimator
State observer
Extended Kalman filter over the cell voltage + current measurement combines well with the Ah-counter to suppress drift from noisy current sensing in real packs.
05
Run + capture

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');
MATLAB MCP server
Tool bridge
Exposes 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.
ode23t (stiff)
Solver
Pinned in the parameter file. The cell electro-thermal system is stiff because the cell-level RC time constant is orders of magnitude faster than the thermal ODE. ode23t handles both without small-step starvation.
EnablePacing OFF
Wall-time guard
Pacing pins simulated time to wall time. Lethal for sweeps. The MATLAB script 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.
exportgraphics
Plot capture
Writes high-DPI PNGs straight from the figure handle, no print resolution dance. Each plot in this page comes from a single exportgraphics(f, …, 'Resolution', 150) call.

03 · Inside the model

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.

Simulink block diagram of SSB_Model.slx (iter5f) — TMS, BMS, CellArray, PowerLimiter and Signal_Monitor wired through the electro-thermal feedback loop, with all log and delay blocks on the cosmetic layout.
SSB_MODEL.SLX · 5 SUBSYSTEMS · ITER5F BASELINE
CELL STACK CROSS-SECTION (NOT TO SCALE) Li-metal PEO+LLZO COMPOSITE LIF/LLZO NMC622 POWER-OPTIMISED COLLECTOR ANODE ELECTROLYTE CATHODE C.C. LI⁺ TRANSPORT DIRECTION (DISCHARGE) Architecture highlights Anode Lithium-metal · high theoretical capacity Electrolyte Composite PEO + LLZO ceramic filler Membrane Ultra-thin for high energy density Transport Single-ion copolymer for fast Li⁺ Activation Reduced vs neat amorphous PEO Cathode NMC622 in a power-optimised multi-stack Interface Low-resistance LiF/LLZO buffer coating

CELL STACK CROSS-SECTION · LI-METAL | COMPOSITE PEO/LLZO | NMC622

04 · Real-run results

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.

Table of contents of the auto-generated SSB_Detailed_Report.pdf — 32 numbered sections covering system overview, simulation setup, architecture, cell physics, thermal management, BMS, simulation execution and results, plus iterations, validation, debugging history and conclusions.
AUTO-PDF · SSB_DETAILED_REPORT.PDF · 32 SECTIONS · GENERATED FROM SIM DATA

05 · Engineering constraints

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.

Solver pinned
ode23t (stiff)
Stiff DAE solver. The cell electrical RC time constant is orders of magnitude faster than the thermal ODE; ode23t survives both without step starvation.
Pacing
EnablePacing must be OFF
Pacing pins sim time to wall time, which is fine for demo runs but lethal for sweeps. Every script set_params it off before sim(); CLAUDE.md elevates the rule to a golden rule.
Master params
Single source of truth
All physics in params/ssb_params.m. AI agents may not modify chemistry or geometry without explicit approval — change one place or none.
Model backups
Every iteration saved
Backups follow 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.
Reports
Real data only
No fabricated numbers, no estimates, no fallback values. If the simulation didn't produce the data, the report says so explicitly. The auto-PDF is generated from simOut, never from defaults.
Test suite
Physics assertions gate iterations
Arrhenius behaviour of R0, PEO conductivity drop below 60 °C, terminal voltage nominal, heat generation, temperature-rise rate, cold-temperature degradation. Tests are immutable; failing tests block iterations.
Driver telemetry
Public race data only
FastF1 streams the F1 official timing feed. No paddock telemetry, no team data, no proprietary maps — every input is public information, and the throttle/brake mapping is published in the page itself.
Project framing
Personal · no employer data
A self-directed exploration outside work. The chemistry and pack sizing are drawn from public solid-state battery literature; nothing in the model represents employer information. Source repository is private.

06 · Performance numbers

Bench numbers from a real lap.

All values below are from the single 2026 Miami GP race-winner-lap simulation.

Pack peak

350 kW
Maximum pack discharge power on full-throttle pulls — exactly on the iter-5f design point.

Sim wall time

4.69 s
91.76 s of physics in 4.69 s of wall time on a consumer laptop. About 20× faster than real-time — which is what makes parameter sweeps a one-coffee operation.

Coolant T peak

65.0 °C
Peak coolant temperature, well inside the BMS over-temperature threshold. Coolant stabilises in the 61–63 °C band across the lap.

Race lap simulated

1:31.968
Fastest race lap of the 2026 Miami GP — 91.76 s of telemetry-derived ERS current driven into the live solid-state pack.

07 · Full tech stack

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

08 · Lessons learned

What the integration taught.

Lesson 01
An MCP server attached to a live, persistent MATLAB session beats a headless one for this kind of work. Warnings stream back, plot windows stay open between calls, and the engineer can drop into the desktop interactively without losing the agent's workspace state.
Lesson 02
Treat the simulation as an experimental apparatus, not as a piece of code. The disciplines that pay off are boring: one master parameter file, named-iteration backups, an immutable test suite, no fabricated outputs. They sound bureaucratic but they are what kept the iteration loop fast and trustworthy across thirty-plus model revisions.
Lesson 03
Solver and pacing settings matter as much as physics. The cleanest model is useless if 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.
Lesson 04
FastF1 + a deliberately simple telemetry-to-current map gives defensible inputs without paddock data. The mapping is published in the page; anyone can read the throttle/brake assumption, disagree with it, and propose a better one without needing access to anything that is not already public.
Lesson 05
The biggest lesson is that with the right human input and methodology — a clear contract, explicit golden rules, and consistent HIL refinement sessions — Claude Code can drive a robust simulation suite end-to-end, faithfully following the rules and contracts the engineer defined. The compound effect on productivity is dramatic: parameter sweeps, plot generation, report compilation and result curation become an order of magnitude faster than any traditional simulation workflow. The fact that MathWorks themselves now publish official MATLAB and Simulink agentic toolkits and skills for AI coding agents is the clearest proof that the industry has crossed the same threshold.