The problem
Equivalent-circuit models are the workhorse of BMS estimation, power-limit calculation and pack simulation, but their parameters must be measured for each cell type and vary with SOC and temperature. This project builds a low-cost identification bench from the kit, shows how parameters change with SOC and quantifies the accuracy gained by adding a second RC branch.
Objectives
- Design a pulse-test sequence across the SOC range with the kit's switchable loads.
- Capture the voltage step at pulse edges with fast ADC sampling.
- Fit 1RC and 2RC models and their dependence on SOC.
- Validate both models on a held-out dynamic profile and compare error against complexity.
- Report parameter uncertainty and repeatability.
What you need
From the EV Embedded Development Kit
- STM32F103C8T6 microcontroller unit (Arm Cortex-M3)
- 1S battery with connector and T-sense input
- Load section: three switchable resistive loads with LEDs
- Charge/discharge control relay
- Battery charging unit with its own switch
- I2C and SPI buses to the onboard devices
- Serial UART interface
Software
- STM32CubeIDE
- Embedded C with STM32 HAL
- Python with NumPy, SciPy, pandas and matplotlib
- MATLAB with System Identification or Simscape (optional)
Extra parts
- INA219 I2C current and power monitor breakout — Parameter fitting needs the actual current during each pulse, not a nominal value; the kit lists no current sensor. The INA219 measures it on the I2C bus while the STM32 ADC samples voltage fast enough to catch the instantaneous step.
This project uses the kit's lithium cell. Respect polarity, never short the terminals, and don't leave the cell charging unattended.
Key concepts
- Ohmic resistance R0
- Seen as the instantaneous voltage jump when current changes. Measuring it needs samples taken within a few milliseconds of the edge.
- RC branches
- Each resistor–capacitor pair models a polarisation process with its own time constant, from seconds (charge transfer) to minutes (diffusion).
- Model order selection
- More RC branches fit better but add parameters and computation. Comparing validation error against complexity shows whether the extra branch is worth it.
- Non-linear least squares
- Fitting exponential recovery curves means minimising the squared error between measured and modelled voltage by iterative optimisation, for example SciPy's curve_fit.
Step-by-step guide
- 1
Plan the pulse test
Design a sequence that, at each of about ten SOC levels, applies a discharge pulse of fixed length (for example 30 s) on one load combination, then rests long enough to capture the recovery (several minutes), then removes about 10 per cent of capacity before the next level. Include two pulse amplitudes using different load combinations to check linearity. Also plan a held-out validation profile with random pulses.
Checkpoint: A written pulse-test and validation plan with expected durations and supervision arrangements.
- 2
Set up hardware and measurement
Disconnect the cell, install the INA219 shunt in series with one cell lead, connect it to the I2C bus and reconnect the cell checking polarity. Enable DIP switches for battery sense, loads, relay, T-sense, I2C and UART. Configure the ADC with a timer trigger at 1 kHz and DMA into a ring buffer for voltage, and read the INA219 at its fastest practical conversion setting. Never leave the cell charging unattended.
Checkpoint: A 1 kHz voltage stream and a current stream with consistent timestamps at a pulse edge.
- 3
Synchronise load switching and sampling
Switch the load from the same timer context that marks the sample index, so the exact sample at which current changes is known. Capture a pre-trigger window of 50 ms and a post-trigger window of a few seconds at full rate, then reduce to 10 Hz for the long recovery to keep the data volume manageable. Send records over UART with DMA.
Checkpoint: Plots of a single pulse edge showing the voltage step within one or two samples of the logged switch time.
- 4
Run the characterisation
Start from a supervised full charge and a long rest. Run the pulse sequence automatically with a state machine, recording temperature with every pulse. Stop at the cut-off voltage and abort on temperature limits. Record the room temperature. Repeat the whole test on a second day to estimate repeatability. Check the logs after each SOC level so a failed pulse can be repeated before moving on. Keep the room temperature as steady as you can.
Checkpoint: Two complete datasets with ten SOC levels each and no aborted pulses.
- 5
Extract R0
For each pulse edge, compute R0 = ΔV / ΔI using the voltage just before the edge and the first sample after it, at both switch-on and switch-off. Compare the two and check against sample timing: if R0 grows when you use a later sample, some fast polarisation is being included. Plot R0 against SOC for both pulse amplitudes. Repeat the extraction for both pulse amplitudes to check the cell behaves linearly.
Checkpoint: An R0 against SOC plot with switch-on and switch-off estimates that agree within a stated margin.
- 6
Fit 1RC and 2RC models
Fit the relaxation after each pulse with one exponential and with two, using scipy.optimize.curve_fit with sensible initial guesses and bounds (time constants positive and ordered). Convert amplitudes and time constants into R1, C1, R2, C2 using the pulse current. Check residuals for structure; a 1RC fit often leaves a systematic tail that the 2RC fit removes. Save the fitted values and their covariance matrices for every pulse so later steps can show uncertainty.
Checkpoint: Residual plots for both fits at three SOC levels, with RMS residuals reported.
- 7
Build SOC-dependent parameter tables
Arrange the fitted parameters against SOC and smooth them sensibly. Note where fits are poorly conditioned, often at high SOC with short time constants. Export tables that a firmware model can use, keeping the format ready for fixed-point use on the STM32 later. Compare the tables from the two test days to see which parameters are repeatable and which drift. Choose the SOC spacing of the final table so the model error from interpolation stays small compared with the fit error.
Checkpoint: Parameter tables for both model orders with confidence intervals from the fit covariance.
- 8
Validate on held-out data
Run the random-pulse validation profile from a full charge. Simulate both models using measured current and the parameter tables, then compare simulated with measured terminal voltage. Report RMS and maximum error overall and in high, mid and low SOC regions, and the improvement from the second branch. Also simulate a model with fixed, SOC-independent parameters as a baseline, so the benefit of the SOC tables is measured rather than assumed. Plot the error against time to see where each model struggles.
Checkpoint: A validation plot and table showing voltage error for 1RC and 2RC models.
- 9
Run the model on the MCU
Port the 1RC and 2RC voltage models to the STM32 in fixed-point form and run them in real time alongside the measurement. Measure cycles per update with the DWT cycle counter and compare their predictions against the PC simulation. This shows whether the model is ready for an embedded estimator. Choose scaling so voltages are held in microvolts and time constants as integer multipliers per step. Run the embedded model for a full profile and log its output alongside the measured voltage.
Checkpoint: On-board model voltage matches the PC simulation within a few millivolts with measured cycle costs.
- 10
Report and discuss
Present the bench, test design, extraction methods, parameter tables with uncertainty, validation results and repeatability between days. Discuss the limitations: low current range, one temperature, and pulses limited to the fixed load levels. Recommend which model order to use for SOC estimation on this MCU and why. Include a short guide on how another team could repeat the bench with their own cell, covering pulse design, sampling rates and fitting settings, and list the settings that changed results most during your work.
Checkpoint: A report with a quantified recommendation for model order backed by validation error and cycle cost.
Testing & validation
- R0 from switch-on and switch-off edges agree.
- Fit residuals and parameter confidence intervals for each SOC level.
- Held-out profile voltage error for 1RC and 2RC models.
- Day-to-day repeatability of parameters.
- Embedded model output against PC simulation.
Expected results
Measured 1RC and 2RC parameter tables for the kit cell across SOC, validated on a separate profile, with a quantified comparison of accuracy against computational cost on the STM32.
Research angle for your M.Tech thesis
Research questions: how many RC branches are justified for a small Li-ion cell at low C-rates, and how sensitive are fitted parameters to sample timing and pulse design? Metrics: validation voltage RMS error, parameter confidence intervals, repeatability, cycles per model update. Baselines: 1RC model and a fixed-parameter model. Comparing the bench's results with parameters fitted from a public dataset such as CALCE using the same method helps establish method validity. A clear study of identification-design choices on a low-cost bench, with open data and scripts, could support a workshop or conference paper.
Take it further
- Repeat at a second ambient temperature to add a temperature axis.
- Identify parameters online with recursive least squares.
- Use the model in an EKF SOC estimator.
- Compare with a fractional-order model fitted offline.
Viva and review questions
How do you measure R0?
From the voltage jump divided by the current change at a pulse edge, using samples taken within a few milliseconds so slower polarisation is not included.
Why might a second RC branch be needed?
Polarisation has fast and slow components. One time constant cannot fit both, which shows up as structured residuals; a second branch captures the slow tail.
Why keep a separate validation profile?
Fitting error on the identification data is optimistic. Only error on data not used for fitting shows how well the model predicts.