The problem
A BMS that trusts a faulty sensor can let a cell overcharge or overheat, and safety standards expect sensor and cell faults to be detected and handled. Simple range checks catch only gross failures. Model-based diagnosis compares measurements with what a cell model predicts, so subtle faults such as offsets and drift can be detected and told apart, but thresholds must be designed to avoid false alarms.
Objectives
- Define a fault set: voltage-sensor offset and stuck value, current-sensor offset, temperature-sensor open or stuck, and abnormal resistance rise.
- Generate residuals from an electrical and thermal model and a structured residual set for isolation.
- Design detection thresholds with a statistical method and measure false-alarm and missed-detection rates.
- Implement detection on the STM32 and report diagnostic trouble codes over CAN.
- Validate with injected faults on hardware and with offline datasets.
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
- CAN bus interface with screw terminal
- I2C and SPI buses to the onboard devices
- Serial UART interface
Software
- STM32CubeIDE
- Embedded C with STM32 HAL
- Python with NumPy, SciPy, pandas, matplotlib and python-can
- MATLAB/Simulink (optional)
Extra parts
- INA219 I2C current and power monitor breakout — Current-sensor faults are part of the fault set, so a real current sensor is needed; the kit lists none.
- USB-CAN adapter for the PC — The board has one CAN node; a USB-CAN adapter lets a PC receive and log the diagnostic frames and act as a vehicle-side tester.
This project uses the kit's lithium cell. Respect polarity, never short the terminals, and don't leave the cell charging unattended.
Key concepts
- Residual
- The difference between a measurement and its model-based prediction. Near zero when healthy, it shifts in a characteristic way when a fault occurs.
- Structured residuals
- A set of residuals designed so each fault affects a different subset. The pattern of which residuals are triggered isolates the fault.
- CUSUM test
- Cumulative sum of residual deviations from zero; it detects small persistent shifts faster than a fixed threshold at the same false-alarm rate.
- Diagnostic trouble code
- A coded fault report with status, such as confirmed or pending, sent to other ECUs or a service tool.
Step-by-step guide
- 1
Define faults, requirements and protocol
List the faults with magnitudes of interest, for example a 20 mV voltage offset, a 20 mA current offset, a stuck T-sense value and a 30 per cent resistance rise. For each, define the required detection time and acceptable false-alarm rate. Write the evaluation protocol: fault-free data for threshold design, separate fault-free data for false-alarm measurement, and injected-fault runs. Name baselines: range and rate checks only, and a simple fixed-threshold residual.
Checkpoint: A fault table with magnitudes, detection-time targets and false-alarm targets, plus the evaluation protocol.
- 2
Set up the hardware and CAN
Disconnect the cell, install the INA219 shunt in series with one cell lead, connect it to I2C and reconnect checking polarity. Enable DIP switches for battery sense, T-sense, loads, relay, I2C, CAN and UART. Configure bxCAN at 500 kbit/s (APB1 at 36 MHz, prescaler 4, 15 + 2 time quanta) and connect the USB-CAN adapter to the screw terminal with 120 Ω termination at both ends. Confirm frames reach the PC with python-can.
Checkpoint: A test frame sent from the board every second is received and logged on the PC.
- 3
Build and identify the models
Identify an electrical model (OCV–SOC table plus 1RC) and a lumped thermal model for the kit cell, using pulse and cooling tests. Validate them on held-out data and record the residual statistics when healthy: mean, standard deviation and autocorrelation. These statistics are the foundation of threshold design, so collect them across different load profiles and days. Note any operating conditions where the model fits poorly, such as low SOC.
Checkpoint: Healthy residual distributions for voltage and temperature on held-out data.
- 4
Design structured residuals
Create residuals that react differently to each fault: voltage residual from the electrical model driven by current; a charge-balance residual comparing coulomb-counted SOC with OCV-based SOC after rests; a temperature residual from the thermal model; and analytical redundancy using the known load resistance to estimate current as V / R, compared with the INA219 reading. Build a fault-signature matrix showing which residuals each fault affects.
Checkpoint: A signature matrix in which every fault has a distinct pattern, or an explanation where two faults cannot be isolated.
- 5
Design detection tests
For each residual, design a CUSUM or generalised likelihood-ratio test with parameters set from the healthy statistics to meet the false-alarm target. Compare with a fixed threshold at the same false-alarm rate. Handle the model's known weak spots, such as the flat OCV region, by adapting thresholds or disabling a residual in conditions where it is not informative. Document every chosen threshold with the data and calculation behind it.
Checkpoint: Offline receiver-operating curves for each test on recorded data with simulated faults added.
- 6
Implement fault injection
Build a firmware fault-injection layer that adds offsets, freezes a sensor value or scales a reading, switched on by a CAN or UART command at a logged time. For physical faults, use safe methods only: disconnect the T-sense input with the board unpowered to create an open circuit, or switch an extra load to emulate abnormal drain. Never create a short circuit on the cell.
Checkpoint: Each injected fault is applied and removed on command, with the injection time logged.
- 7
Implement detection and isolation on the STM32
Port the models, residuals and tests to fixed-point C in a 100 ms task. Isolate faults by matching triggered residuals to the signature matrix. Manage fault states: pending, confirmed after the detection test, healed after a recovery period. On a confirmed safety-relevant fault, open the relay. Measure cycles with the DWT counter. Keep the diagnostic code separate from the protection code, so a diagnostic bug cannot stop the basic range-check protection from working. Log every state change with a timestamp.
Checkpoint: On-board detection of each injected fault with the right isolation, within the CPU budget.
- 8
Report diagnostics over CAN
Define a diagnostic frame with fault code, status bits (pending, confirmed, healed), occurrence counter and a freeze-frame of voltage, current and temperature at detection. Send it on change and periodically. Write a PC tool with python-can that decodes and logs these frames and shows active faults. Add a clear-faults command from the PC so tests can start from a known state. Document the frame layout in a DBC-style table and decode it with the same definition in the PC tool, so the embedded and PC sides cannot drift apart.
Checkpoint: The PC tool lists the correct fault code and freeze-frame for each injected fault.
- 9
Run the evaluation campaign
Run many hours of fault-free operation across profiles to measure false alarms, then repeat injected-fault runs for each fault at several magnitudes and operating points. Record detection time, isolation correctness and missed detections. Compare with the baselines on the same runs. Randomise the order of fault types and magnitudes, and inject each fault at different SOC levels and load profiles, so results are not biased by when in a test the fault happens. Keep the fault-free data used for false alarms separate from the data used to design thresholds.
Checkpoint: A results table of false-alarm rate, detection time, isolation accuracy and missed detections for every fault and baseline.
- 10
Analyse and write up
Present minimum detectable fault sizes, the trade-off between detection time and false alarms, and where isolation fails. Discuss how model error limits sensitivity and how the method would scale to a series pack. Release code, fault-injection scripts and datasets. Compare the results with the targets set in the first step and explain each shortfall. Plot detection time against fault size for each test so readers can see the minimum detectable fault clearly, and include the confusion matrix for isolation.
Checkpoint: A thesis chapter and paper draft with reproducible results and explicit limitations.
Testing & validation
- Healthy residual statistics across profiles and days.
- False-alarm rate over long fault-free runs.
- Detection time and isolation accuracy for each injected fault and magnitude.
- Comparison with range-check and fixed-threshold baselines.
- Diagnostic frames decoded correctly on the PC over CAN.
Expected results
A model-based FDI scheme on the STM32 with structured residuals, statistically designed thresholds, CAN-reported fault codes and a quantified evaluation of detection performance against simple baselines.
Research angle for your PhD
Research questions: what are the minimum detectable sensor and cell faults for a model-based scheme on a low-cost BMS, and how well can they be isolated given model error? Metrics: false-alarm rate, detection delay, isolation accuracy, minimum detectable fault size, CPU cost. Baselines: range and rate checks, fixed-threshold residuals. Public datasets such as NASA PCoE can provide healthy data with ageing for offline threshold robustness tests. A rigorous comparison with a clear injection methodology and open data could support a conference or journal paper on low-cost BMS diagnostics.
Take it further
- Use an adaptive observer so model parameters track ageing and reduce false alarms.
- Simulate a series pack and add cell-to-cell comparison residuals.
- Compare with a data-driven anomaly detector trained on healthy data.
- Map the diagnostic frames to a UDS-style read DTC service.
Viva and review questions
What is the difference between detection and isolation?
Detection says something is wrong; isolation says which fault it is. Isolation needs residuals that respond differently to each fault.
Why use CUSUM rather than a fixed threshold?
CUSUM accumulates small persistent deviations, so it detects small offsets faster at the same false-alarm rate.
How did you get analytical redundancy for current?
With a known load resistance, current can also be estimated as cell voltage divided by that resistance, which can be compared with the INA219 reading.
Why do you need a USB-CAN adapter?
The board has a single CAN node, so another node is needed to receive the diagnostic frames and acknowledge them on the bus.