The problem
Every EV charger and on-board BMS charges lithium-ion cells with some form of CC–CV profile, and the termination logic decides how full the cell gets, how long charging takes and how safely faults are handled. Students often know the curve from a datasheet but have never built the controller that produces it. This project models the power stage, the cell and the supervisory logic together so the trade-offs become measurable.
Objectives
- Model a lithium-ion cell or small pack with a battery block and a controllable current source.
- Design current and voltage control loops that hand over smoothly from CC to CV.
- Implement pre-charge, CC, CV, termination and fault states in Stateflow.
- Quantify the effect of the CV cut-off current on charge time and delivered capacity.
- Test fault handling for over-temperature, over-voltage and timeout.
What you need
Tools and toolboxes
- Simulink — Top-level model, control loops, signal logging and the Simulation Data Inspector.
- Simscape Electrical — Battery block (or a Simscape equivalent-circuit cell) and the controlled current source that represents the charger output.
- Stateflow — Charge-state machine: pre-charge, CC, CV, done and fault, with guarded transitions and timers. A MATLAB Function block with a switch-case can replace it on a base licence.
Software
- MATLAB R2023b or later
- Simulink
- A published cell datasheet for capacity, voltage limits and charge current
Extra parts and data
None beyond the software above.
Key concepts
- CC–CV charging
- The charger first pushes a fixed current until the cell reaches its maximum voltage, then holds that voltage while the current decays. The CV phase lets the cell absorb the last part of its capacity without overshooting the voltage limit.
- Termination current
- Charging ends when the CV-phase current falls below a threshold, typically a small fraction of the C-rate such as C/20. A higher threshold shortens charge time but leaves capacity unused.
- Pre-charge
- A deeply discharged cell below a minimum voltage is charged at a low current first, to recover it gently and detect a damaged cell before full current is applied.
- Bumpless transfer
- When control passes from the current loop to the voltage loop, the commanded current must not jump. Initialising the voltage-loop integrator to the present current gives a smooth handover.
Step-by-step guide
- 1
Write the charging specification
Pick an example cell, for instance a 3.2 Ah, 3.6 V nominal NMC cylindrical cell with a 4.2 V maximum, 2.5 V minimum and a 1C (3.2 A) maximum charge current. Write the profile: pre-charge at C/10 below 3.0 V, CC at 0.5C, CV at 4.2 V, termination at C/20, a safety timer and a 45 degC temperature cut-off. Put all values in a MATLAB script that loads them into the base workspace, so every later block reads named parameters rather than typed numbers.
Checkpoint: A parameter script that runs without errors and a one-page specification table with every threshold.
- 2
Model the cell
Place the Battery block from Simscape Electrical (Specialized Power Systems) or, in the Simscape foundation domain, a Battery (Table-Based) block. Enter capacity, nominal and maximum voltage and internal resistance from the datasheet and set initial SOC to 10 per cent. Drive it with a Controlled Current Source and add voltage and current sensors. Use a variable-step solver such as ode23t, or a fixed step of 1 ms with a local solver if using the foundation library.
Checkpoint: A constant 1.6 A charge raises terminal voltage smoothly from about 3.4 V towards 4.2 V, and SOC rises at the expected 0.5C rate.
- 3
Build the current loop
The charger is treated as an ideal current source with a first-order lag (a Transfer Fcn of 1/(tau·s+1) with tau around 10 ms) to represent the power stage bandwidth. Add a current reference input and a Saturation block limiting output to the maximum charge current. Confirm the source follows step changes in the reference. Keeping the power stage this simple keeps the project focused on charging logic rather than switching detail.
Checkpoint: A step in current reference from 0 to 1.6 A settles within about five time constants with no overshoot.
- 4
Add the voltage loop
Design a PI controller whose input is the voltage error (4.2 V minus terminal voltage) and whose output is a current reference, limited between zero and the CC setpoint. Take a Min block of the CC setpoint and the voltage-loop output so the lower request always wins; this gives a natural CC-to-CV transition. Enable the integrator's anti-windup (clamping) in the PID Controller block. Tune Kp and Ki so the voltage settles at 4.2 V without exceeding it by more than about 5 mV.
Checkpoint: In a full charge run the current stays flat at 1.6 A, then decays smoothly once voltage reaches 4.2 V, with voltage overshoot under 5 mV.
- 5
Build the Stateflow supervisor
Create a chart with states PreCharge, CC, CV, Done and Fault. Inputs are cell voltage, current, temperature and elapsed time; outputs are the current setpoint and an enable flag. Transitions: PreCharge to CC when voltage exceeds 3.0 V; CC to CV when voltage reaches 4.2 V; CV to Done when current stays below C/20 for 10 s, using after(10,sec) with a condition; any state to Fault on over-temperature, over-voltage or timeout. Set the chart update to discrete with a 10 ms sample time.
Checkpoint: The chart animation steps through PreCharge, CC, CV and Done in order during a charge from 5 per cent SOC.
- 6
Integrate and log
Connect the supervisor's setpoint to the Min block and its enable flag to gate the current source. Mark voltage, current, SOC, temperature and active state for logging and open the Simulation Data Inspector. Add a simple thermal model, a first-order lumped mass with I²·R heating and convection to ambient, so the temperature input is meaningful. Run a full charge from 5 per cent SOC and save the run.
Checkpoint: Simulation Data Inspector shows the textbook CC–CV curve, state changes at the right instants and a final SOC above 95 per cent.
- 7
Test the fault paths
Write test runs that force each fault: raise ambient temperature so the cell crosses 45 degC, inject a sensor offset so measured voltage jumps above 4.25 V, and shorten the safety timer. For each, confirm the chart enters Fault, the current drops to zero within one sample and the charger does not restart without a reset input. Script these runs with sim() and Simulink.SimulationInput objects so they can be repeated after every model change.
Checkpoint: All three fault scenarios drive the current to zero and latch the Fault state, confirmed by an automated script printing pass for each.
- 8
Sweep the termination threshold
Use a parameter sweep over the termination current (C/10, C/20, C/50) and the CC current (0.3C, 0.5C, 1C). For each run, record total charge time, time spent in CV and delivered ampere-hours. Plot charge time against final SOC. Explain why most of the extra time at low cut-off currents is spent gaining the last few per cent of capacity, and what that means for a fleet that charges overnight versus one that needs a quick top-up.
Checkpoint: A table and plot showing charge time falling and delivered capacity falling as the termination current rises.
- 9
Write up results
Present the model structure, parameter table, control design, the Stateflow chart and the test results. Include the charging-curve figure, the sweep plot and the fault-test table. State the limitations clearly: an ideal power stage, a single cell, a lumped thermal model and no ageing. Explain how the same logic scales to a pack, where the BMS must also limit charge on the highest cell voltage, not the average.
Checkpoint: A report with reproducible figures generated by one script from a clean MATLAB session.
Testing & validation
- CC–CV curve shape with smooth handover and voltage overshoot under the stated limit.
- Delivered capacity close to rated capacity at a C/20 cut-off.
- Automated fault tests for over-temperature, over-voltage and timeout all pass.
- Sweep results that follow the expected trend of time against capacity.
Expected results
A reusable Simulink charger model with a Stateflow supervisor, a verified CC–CV curve, fault-handling tests and a quantified trade-off between charge time and delivered capacity.
Take it further
- Replace the ideal source with a switched buck converter and its own current loop.
- Add temperature-dependent charge-current derating as in many cell datasheets.
- Extend to a 4S pack with cell imbalance and charge limiting on the highest cell.
- Compare CC–CV with a multi-stage constant-current profile.
Viva and review questions
Why does a lithium-ion charger switch from constant current to constant voltage?
Holding current constant beyond the maximum voltage would push the cell above its safe limit because of the voltage drop across internal resistance. Holding the voltage lets current fall naturally as the cell fills.
What sets the termination current, and what happens if it is too low?
It is a trade-off between capacity and time, usually given in the datasheet. Too low a value adds a long tail of charging for little extra capacity and keeps the cell at high voltage longer.
Why use a Min block between the CC setpoint and the voltage-loop output?
It always applies the smaller of the two current requests, so the voltage loop takes over automatically when the cell reaches its limit, without a hard switch that would cause a current step.
Learn it at DIYguru
These DIYguru courses and programmes teach what this project needs.
