Battery Management Systems · State Estimation · Tutorial
State Estimation Filters for SOC in Battery Management Systems
A precise, technical guide to Coulomb Counting, Kalman Filter, Extended Kalman Filter, Unscented Kalman Filter, and Particle Filter — how each works, why it matters, and when to use it for State of Charge estimation.
Why SOC Estimation Demands Sophisticated Filtering
State of Charge (SOC) — the fraction of maximum charge remaining in a battery — cannot be measured directly. It must be inferred from measurable quantities: terminal voltage V, current I, and temperature T. This makes SOC a hidden state estimation problem, where sensor noise, model uncertainty, and battery aging all conspire against accuracy.
Simple Coulomb counting accumulates current error over time. Open-circuit voltage (OCV) lookup requires rest periods impractical in real systems. Model-based state observers — the four filters covered here — fuse both measurement and model information, providing optimal (or near-optimal) estimates in the presence of noise. Accurate SOC drives charge termination, power limits, balancing, and lifetime predictions inside every BMS.
Battery Model Foundation — Thevenin Equivalent Circuit
All four filters are built on an underlying battery model. The most common is the Thevenin (RC) equivalent circuit model:
τ = R₁C₁ (RC time constant), η = Coulombic efficiency, Q_n = nominal capacity, w = process noise, v = measurement noise
Coulomb Counting
Core Idea
Coulomb Counting (also called Ampere-hour integration) is the simplest and most widely used SOC estimation method. It tracks SOC by integrating the battery current over time: charge flowing out reduces SOC; charge flowing in increases it. No battery model is required — only a current sensor and a clock. It is the process model inside all four Kalman-family filters.
Where It Fits in BMS
- Used standalone in low-cost BMS (EV scooters, power tools)
- The process equation inside every KF, EKF, UKF, and PF
- Foundation for all model-based estimators — they correct its drift
- Requires only current sensor — no voltage model needed
- Works during high-rate charge/discharge when voltage is noisy
Core Equation
η = Coulombic efficiency (≈ 0.99–1.0 for Li-ion discharge; use measured value for charging), Q_n = nominal capacity [Ah], Δt = sampling interval [s], I = current [A] (positive = discharge)
How the Algorithm Works
Conceptual Explanation
Coulomb Counting is analogous to tracking water level in a tank by measuring only the flow rate into and out of it — never looking at the water level directly. If you know how full the tank was to start with, and you sum up every litre that flows in and out, you always know the current level. The problem: any error in the flow meter (current sensor offset, gain drift) accumulates permanently. A 1% current sensor error leads to 1% SOC error per full cycle — and batteries do thousands of cycles.
Initialisation is critical. The method requires an accurate SOC(t₀). The most reliable way is to let the battery rest until OCV stabilises, then look up SOC from the OCV–SOC table. In a vehicle, this means using the “ignition-off rest” period. If the battery never rests (e.g., grid storage), Coulomb counting accumulates error indefinitely without a reference reset.
The discrete update is just a subtraction (or addition during charge). At each sampling interval Δt, multiply the measured current by Δt to get the charge transferred in Coulombs (or Ampere-seconds), divide by the nominal capacity Q_n in the same units, and subtract from SOC. Multiply by Coulombic efficiency η to account for the fact that not all charge going in comes back out — some is lost to heat and side reactions.
Why the filters are needed: Coulomb counting has no self-correction mechanism. If SOC(t₀) is wrong, or if the current sensor has a DC offset of 0.1A, the error grows linearly with time. The Kalman-family filters use Coulomb counting as their prediction step but add a measurement update from the voltage sensor to continuously correct this drift — this is the fundamental reason model-based estimation outperforms standalone Coulomb counting.
Step-by-Step Algorithm
Rest the battery until terminal voltage equals OCV (typically 30 min – 2 hr depending on cell chemistry). Look up SOC from the OCV–SOC characterisation table. This is the only moment Coulomb counting uses voltage — and only to initialise. Alternative: if the cell was fully charged last cycle and SOC(end) was reached, use that as the starting point.
Use the cell datasheet capacity at room temperature. For an aged cell, Q_n must be updated — a 20% capacity fade means Q_n shrinks by 20%, and if the old Q_n is kept, SOC will be overestimated. This is the SOH interaction: Coulomb counting accuracy degrades as the battery ages unless Q_n is recalibrated periodically.
Read the current sensor (Hall effect or shunt resistor) at the sampling instant k. Apply any known offset calibration. Current sensor accuracy is the single biggest factor in Coulomb counting accuracy. A shunt-based measurement with a high-quality ADC (16-bit, ±0.05% accuracy) gives substantially better results than a Hall sensor (±1–3% typical).
Multiply the instantaneous current by the time step. For a 10Hz BMS (Δt = 0.1s), a 100A discharge transfers 100 × 0.1 = 10 As = 0.00278 Ah per step. For high-accuracy systems, use the trapezoidal rule: ΔQ = (I(k) + I(k−1)) / 2 × Δt, which better approximates the integral between samples.
During discharge, every Coulomb that flows out reduces SOC by a full Coulomb (η = 1.0 assumed). During charge, not all charge going in is stored — lithium plating, electrolyte decomposition, and heat absorb some fraction. Typical Li-ion η at room temperature is 0.99–0.995. At low temperatures (−20°C), η can drop to 0.90 or lower, requiring temperature-dependent η(T) tables.
Subtract the normalised charge increment from the previous SOC. The negative sign for discharge follows from the convention that positive current means current leaving the battery. After this step, clamp SOC to [0, 1] to avoid physically impossible values caused by sensor noise or model errors.
Report SOC(k) to the BMS supervisor. Go to S-1 at the next sampling instant. The loop continues for the entire battery operating lifetime.
When the charger terminates the CC-CV charge cycle (current drops below I_cutoff, typically C/20), the cell is fully charged and SOC can be hard-reset to 100%. This resets all accumulated drift. Similarly, if the BMS detects a low-voltage cutoff event, SOC can be reset to 0%. These “anchor points” limit the maximum error between resets to the drift accumulated in a single cycle.
If the battery has been at rest for long enough that V_terminal ≈ OCV, use the OCV table to recalibrate SOC. This is especially valuable for LFP cells where the OCV plateau is flat — wait until the cell has fully relaxed, then the voltage reading gives a reliable SOC reference. The model-based filters (EKF, UKF, PF) do this correction continuously at every step, which is their primary advantage over standalone Coulomb counting.
Error Sources and Quantification
Temperature Effects on η
- 25°C: η ≈ 0.995 (Li-ion, discharge)
- 0°C: η ≈ 0.980 — increased internal resistance slows kinetics
- −20°C: η ≈ 0.920 — significant capacity reduction
- 45°C: η ≈ 0.998 — faster kinetics, but accelerated aging
- Use temperature-indexed η(T) table, updated from periodic calibration
Capacity Fade Tracking
- Q_n decreases ~20% by end-of-life (≈ 800–2000 cycles for Li-ion)
- If Q_n is not updated, SOC is overestimated throughout life
- Recalibrate Q_n from full charge-discharge cycles: Q_n_new = ∫I dt from 100% to 0%
- Or use SOH estimator running in parallel (dual EKF, joint PF)
- Monthly recalibration recommended for critical applications
✓ Advantages
- Extremely simple — one equation per sample
- Works at any C-rate including high-power transients
- No battery model or OCV table needed during operation
- Negligible computation — runs on any 8-bit MCU
- Accurate over short time horizons with good sensors
- Forms the predict step in all model-based filters
✗ Limitations
- Requires accurate initial SOC — error in SOC(0) is permanent
- Current sensor offset causes unbounded drift over time
- Does not self-correct — no feedback from voltage measurement
- Q_n must be updated as battery ages (SOH dependency)
- η varies with temperature, C-rate, and aging
- Useless after sensor failures or extended rest without reset
Coulomb Counting vs. Model-Based Filters — The Key Difference
Coulomb counting is an open-loop integrator: it blindly integrates current with no feedback. Any error (sensor offset, wrong Q_n, wrong η) accumulates without bound. The KF/EKF/UKF/PF filters are closed-loop observers: they use Coulomb counting for the prediction step but correct it every sample using voltage measurements. The voltage correction prevents error accumulation — this is exactly why a 5-year-old EV battery with an EKF can still report SOC within ±2%, while standalone Coulomb counting in the same car would have drifted by 10–20% or more. The filters do not replace Coulomb counting — they wrap around it to give it a self-correcting feedback loop.
Kalman Filter
Core Idea
The Kalman Filter is the mathematically optimal recursive estimator for a linear system where all noise is Gaussian. It minimises the mean-squared estimation error by computing a weighted blend of the model’s prediction and the new measurement. The Kalman Gain K decides how much to trust each source.
Assumptions for SOC
- Battery model is linear (OCV–SOC curve must be linearised)
- Process noise
w ~ N(0, Q) - Measurement noise
v ~ N(0, R) - Noise is white (uncorrelated in time)
- Initial state estimate available
Linear State-Space Model
Algorithm — Two-Step Recursion
How the Kalman Filter Algorithm Works
The KF operates as a continuous predict → correct loop that runs every BMS sampling interval (typically 1–10 Hz). Think of it as two people collaborating on a SOC estimate: a modeller who says “based on the current drawn, SOC should now be X” and a sensor reader who says “based on the voltage I just measured, SOC looks like Y.” The Kalman Filter finds the statistically optimal weighted average of these two opinions at every step.
Predict step: The filter takes its current best estimate of SOC (and V_RC) and runs it forward through the linear battery model using the measured current. This gives a new prediction of where the state should be before looking at the new voltage reading. The uncertainty (covariance P) also grows in this step — we become less confident as time passes and model errors accumulate, just like dead-reckoning navigation drifts without landmarks.
Update step: The new terminal voltage measurement arrives. The filter compares it to the voltage the model predicted. The difference — called the innovation — is how surprised the filter is. A large surprise means the model was wrong; a small surprise means the model and sensor agree. The Kalman Gain K (computed from the ratio of model uncertainty to sensor uncertainty) decides how much of this surprise to believe. The SOC estimate is then nudged by K times the innovation. Measurement noise R is large → K is small → trust the model. Model uncertainty P⁻ is large → K is large → trust the measurement.
After the update, uncertainty P shrinks — we learned something from the measurement. The updated estimate and updated P are then fed into the next predict step, creating a self-correcting recursive loop that runs for the entire battery lifetime. The KF is proven to be the minimum variance unbiased estimator for this class of linear Gaussian system — no other algorithm can do better given the same information.
The filter uses the linear state-space model to roll the previous best estimate x̂(k−1) forward by one time step. Matrix A describes how the state evolves on its own (e.g., SOC drains slowly even at zero current), while B·u(k) injects the known input effect — the measured current I(k) multiplied by the Coulomb-counting factor (−η·Δt/Q_n). The superscript ⁻ denotes this is still a prior estimate: the measurement at time k has not yet been used. Think of this as the model saying “given where we were, here is where we expect to be now.”
Uncertainty must also be propagated forward. P(k−1) is the covariance matrix describing how uncertain we were at the last step. Multiplying by A and Aᵀ transforms that uncertainty through the system dynamics. Adding Q (process noise covariance) accounts for the fact that the model is imperfect — battery aging, temperature effects, and unmeasured disturbances all inject additional uncertainty at every step. After this step, P⁻(k) is always larger than P(k−1): prediction always increases uncertainty.
The Kalman Gain K is the heart of the filter — it decides the optimal blend between the model prediction and the new voltage measurement. The numerator P⁻·Cᵀ represents prediction uncertainty projected onto the measurement space. The denominator adds measurement noise R to that projected uncertainty. When prediction uncertainty P⁻ is large relative to R, K is large → heavily trust the measurement. When the sensor is noisy (large R), K is small → rely more on the model prediction. This ratio is computed optimally, minimising the mean-squared estimation error.
The term [y(k) − C·x̂⁻(k)] is called the innovation or residual — it is the difference between what the voltage sensor actually measured and what the model predicted the voltage would be. If the innovation is zero, the measurement perfectly confirms the prediction and no correction is needed. If it is nonzero, K scales that residual and adds a correction to the predicted state. For SOC estimation, a higher measured voltage than predicted pushes the SOC estimate upward; a lower voltage pulls it down.
After incorporating the measurement, uncertainty always decreases. The factor [I − K·C] shrinks P⁻ by the amount of information gained from the sensor. If K is large (measurement was very trusted), P(k) becomes much smaller than P⁻(k). If K ≈ 0 (sensor was unreliable), P(k) ≈ P⁻(k) and little was learned. This updated P(k) is then carried forward as P(k−1) into the next predict step, completing the recursive loop.
✓ Advantages
- Computationally minimal — only matrix multiplications
- Optimal for linear Gaussian systems (proven)
- Simple to implement and tune
- Provides uncertainty estimate alongside SOC
✗ Limitations
- Battery OCV–SOC is nonlinear — linearisation introduces error
- Diverges when model mismatch is large
- Cannot handle non-Gaussian noise (e.g., sensor glitches)
- Fixed linearisation point may not hold across SOC range
Extended Kalman Filter
Core Idea
The EKF extends the KF to nonlinear systems by linearising the system equations around the current state estimate at each time step. This linearisation is done via the Jacobian matrix — the matrix of first-order partial derivatives. The rest of the KF structure is preserved.
Why EKF for SOC?
- OCV(SOC) is strongly nonlinear, especially near full and empty
- EKF linearises OCV curve at each step using its derivative
- Works with the same Thevenin model
- Industry workhorse: used in commercial BMS chips
- Moderate computation — feasible on embedded MCUs
Nonlinear State-Space Model
Jacobian Matrices
Since f and h are nonlinear, KF matrices A and C are replaced by their Jacobians evaluated at the current estimate:
EKF Algorithm
How the Extended Kalman Filter Algorithm Works
The EKF solves the fundamental problem with the standard KF for batteries: the OCV–SOC relationship is strongly nonlinear (especially near full charge and full discharge), making the linear model matrices A and C inaccurate. The EKF’s insight is to re-linearise the model at every time step around the current state estimate, rather than using a single fixed linear approximation for all SOC values.
Predict step: The EKF propagates the state through the exact nonlinear battery equations f(·) — no approximation here. The SOC is updated using true Coulomb counting, and V_RC is updated using the true RC exponential. Only when uncertainty needs to be propagated does the EKF linearise: it computes the Jacobian matrix F(k) (the first-order Taylor expansion of f around the current estimate) and uses it to propagate the covariance. This is analogous to approximating a curved road with a straight tangent line at your current position.
Update step: The measurement Jacobian H(k) is computed — essentially, the slope of the OCV curve at the current predicted SOC. This slope tells the filter how sensitive the terminal voltage is to changes in SOC. A steep OCV slope means voltage measurements are highly informative about SOC; a flat slope (the dreaded LFP plateau) means voltage tells you almost nothing. H(k) is used to compute the Kalman Gain and update the covariance. The state correction again uses the full nonlinear h(x̂⁻) for the innovation — a critical detail that improves accuracy.
The EKF effectively applies a fresh linear approximation at every step, making it far more accurate than a single linearised KF across the full SOC range. The trade-off is that the quality of the approximation depends on how strongly nonlinear the system is locally — if the OCV curve changes shape rapidly (as in NMC cells near 4.1V), the Jacobian from one step may already be stale by the next, potentially causing the filter to diverge without careful Q/R tuning.
Unlike the KF which uses a fixed linear matrix A, the EKF propagates the state through the actual nonlinear model equations f(·). For the Thevenin battery model this means computing SOC via the full Coulomb-counting equation and V_RC via the full RC exponential decay — no approximation here. The nonlinearity only becomes a problem in the next step when we must characterise how uncertainty propagates, which requires a linearisation.
The Jacobian F(k) is the matrix of all first-order partial derivatives of f with respect to the state x, evaluated at the current estimate x̂(k−1). It is the best linear approximation of f at that point — a local tangent plane. For the Thevenin model, F is a 2×2 matrix: the SOC row has ∂(SOC)/∂SOC = 1 and ∂(SOC)/∂V_RC = 0; the V_RC row has ∂(V_RC)/∂V_RC = e^(−Δt/τ) and ∂(V_RC)/∂SOC = 0. This linearisation is valid only near the current operating point.
Uncertainty is propagated using the locally linearised dynamics F(k) rather than the true nonlinear f. This is the key EKF approximation: while the mean is propagated exactly through f, the covariance is only propagated approximately through the Jacobian. If the true nonlinearity is mild near the operating point, this is accurate. If the system is highly nonlinear (steep OCV curve slope changes), the true covariance grows faster than F·P·Fᵀ predicts, causing P to be underestimated — a precursor to filter divergence.
The measurement function h(x) = OCV(SOC) − R₀·I − V_RC is nonlinear due to OCV(SOC). Its Jacobian H(k) is a 1×2 row vector: the first element is dOCV/dSOC (the slope of the OCV curve at the predicted SOC), and the second is −1 (∂h/∂V_RC = −1 directly). The slope dOCV/dSOC is typically obtained by differentiating a polynomial or spline fit to the OCV lookup table. This value is the single most important parameter in the EKF: it determines how strongly voltage measurements can correct the SOC estimate.
The structure is identical to the standard KF, but now H(k) varies at every time step as the OCV slope changes with SOC. When the OCV curve is steep (e.g., near 0% or 100% SOC for NMC cells), H is large, the innovation covariance is large, and K is large — meaning measurements strongly correct the state. When the OCV curve is flat (e.g., 30–70% SOC for LFP cells), H ≈ 0, K ≈ 0, and the filter effectively ignores voltage measurements and relies purely on Coulomb counting — accumulating drift.
A critical EKF design choice: the innovation [y(k) − h(x̂⁻(k))] uses the full nonlinear h function, not the linearised H·x̂⁻. This means the predicted terminal voltage is computed properly as OCV(SOC⁻) − R₀·I − V_RC⁻, and the difference from the actual measured voltage is the true residual. Only the gain K and covariance propagation use the linearised approximation — this hybrid approach preserves accuracy in the correction step even when linearisation is imperfect.
The updated covariance P(k) reflects the reduction in uncertainty after the measurement was incorporated. Note that this formula (the “simple form”) can occasionally produce non-positive-definite P matrices when K is computed with finite-precision arithmetic. The numerically more stable Joseph form P(k) = (I−KH)·P⁻·(I−KH)ᵀ + K·R·Kᵀ is preferred in embedded BMS implementations to prevent covariance matrix corruption over long operating cycles.
⚠ EKF Critical Tuning Parameter: dOCV/dSOC
The Jacobian H depends on the slope of the OCV–SOC curve. In the flat voltage plateau region (30–70% SOC for LFP cells), dOCV/dSOC ≈ 0, making H ≈ 0. This drives the Kalman Gain toward zero, meaning the filter stops correcting from measurements and relies entirely on current integration — exactly when current errors accumulate most. This is the fundamental challenge of EKF-based SOC estimation for LFP chemistry.
✓ Advantages
- Handles nonlinear OCV–SOC relationship
- Computationally efficient (closed-form Jacobians)
- Widely validated in BMS literature
- Implementable on low-power MCUs
✗ Limitations
- Linearisation error can cause divergence
- Requires analytical Jacobian — model must be differentiable
- Underperforms in flat OCV plateau (LFP batteries)
- Accuracy degrades with strong nonlinearity
Unscented Kalman Filter
Core Idea
The UKF avoids linearisation entirely. Instead, it propagates a carefully chosen set of deterministic sample points — called sigma points — through the actual nonlinear functions. The mean and covariance of the output are then computed from these transformed points. This achieves third-order accuracy for Gaussian distributions, vs. EKF’s first-order.
Unscented Transform (UT)
- Select
2n+1sigma points around the mean - Propagate all sigma points through nonlinear function
- Reconstruct mean and covariance from outputs
- No need to compute any Jacobian
- More accurate for highly nonlinear OCV curves
Sigma Point Generation
For an n-dimensional state, 2n+1 sigma points are generated using three tuning parameters: α (spread), β (prior distribution knowledge), κ (secondary scaling):
UKF Algorithm
How the Unscented Kalman Filter Algorithm Works
The UKF takes a fundamentally different approach to the nonlinearity problem: instead of approximating the function (as EKF does with Jacobians), it approximates the probability distribution directly using a small, carefully chosen set of sample points. The key insight, due to Julier and Uhlmann, is that it is easier to approximate a Gaussian distribution than an arbitrary nonlinear function. This is the Unscented Transform.
Sigma point selection: The current state estimate and covariance define an ellipse of uncertainty in state space. The UKF places 2n+1 deterministic sample points — sigma points — at the centre of this ellipse and symmetrically along each axis, at a distance controlled by α. For a 2-state battery model (SOC, V_RC), this means 5 points. Each sigma point is a plausible (SOC, V_RC) scenario — the centre is the most likely, and the outer points capture the edges of the uncertainty region. Crucially, these points are chosen to exactly capture the mean and covariance of the distribution (and, for the covariance weights, even the kurtosis via the β parameter).
Predict step: Each of the 5 sigma points is run independently through the full nonlinear battery equations f(·) — no linearisation, no Jacobian. This produces 5 transformed points in the output space. The predicted mean and covariance are then recovered as weighted sums of these 5 transformed points. Since the actual nonlinear function is evaluated at multiple points rather than one, the curvature of f is implicitly captured — something no first-order Taylor expansion can do. The resulting predicted mean and covariance are accurate to third order for Gaussian distributions.
Update step: The same Unscented Transform is applied to the measurement function h(·). Each sigma point is mapped to a predicted voltage, and their weighted mean and spread form the predicted measurement ŷ and innovation covariance S. The cross-covariance Pₓᵧ (how correlated state uncertainty is with measurement uncertainty) is computed from the same sigma points — this replaces the P⁻·Cᵀ term in the standard KF, again without any Jacobian. The final state correction uses the same innovation structure as the KF and EKF. The result is that the UKF achieves better accuracy than the EKF on the same battery model, with no analytical derivatives required — just function evaluations.
For a 2-state battery model (SOC, V_RC), n = 2, so we generate 2n+1 = 5 sigma points. The centre point χ₀ is simply the current mean estimate x̂. The remaining 4 points are spread symmetrically around the mean: the i-th column of √((n+λ)P) is added to or subtracted from x̂ to form χᵢ and χᵢ₊ₙ. The matrix square root √P is computed via Cholesky decomposition — a stable, efficient numerical method. The spread is controlled by λ: a larger λ places sigma points further from the mean, capturing more of the distribution’s tails at the cost of potentially sampling regions where the nonlinearity is stronger.
Each of the 5 sigma points is independently propagated through the full nonlinear battery model f(·). For each point this means computing: SOC_new = SOC_old − (η·Δt/Q_n)·I and V_RC_new = e^(−Δt/τ)·V_RC_old + R₁(1−e^(−Δt/τ))·I. No linearisation occurs — we evaluate the true nonlinear function at each point. This is the key innovation of the UKF: by sampling around the mean, we capture how the nonlinearity distorts the distribution, something the EKF’s single tangent-line approximation cannot do.
The predicted mean x̂⁻ is a weighted average of all 5 propagated sigma points, using mean weights Wᵐᵢ. The predicted covariance P⁻ is a weighted sum of outer products of the deviations from the mean, using covariance weights Wᶜᵢ. The centre point (i=0) gets a different weight than the outer points (i=1…2n) — this asymmetry is how the UKF captures skewness and higher-order moments of the transformed distribution. Adding Q at the end accounts for process noise, just as in the KF and EKF.
A fresh set of 5 sigma points is generated from the predicted mean x̂⁻(k) and predicted covariance P⁻(k). These are different from the P-1 sigma points because the predicted covariance P⁻ has changed (it grew due to process noise Q). Re-generating ensures the sigma points used for the measurement update accurately represent the current predicted uncertainty — an important consistency requirement of the algorithm.
Each sigma point is mapped to a predicted terminal voltage using the full nonlinear h: V_t = OCV(SOC) − R₀·I − V_RC. Since OCV(SOC) is nonlinear, each of the 5 sigma points produces a slightly different predicted voltage. This captures how uncertainty in SOC translates to uncertainty in terminal voltage — accounting for the curvature of the OCV curve at the current operating point, which the EKF completely misses by using only the slope.
ŷ(k) is the predicted terminal voltage — a weighted mean of the 5 mapped measurements. S(k) is the innovation covariance: a weighted sum of squared deviations of each mapped point from ŷ, plus sensor noise R. A large S(k) means the filter has high uncertainty in what voltage it should see; a small S(k) means it has a narrow expectation. The innovation S(k) plays the role that (C·P⁻·Cᵀ + R) played in the standard KF, but is computed entirely from nonlinear propagation — no Jacobian involved.
Pₓᵧ is the cross-covariance between the predicted state and predicted measurement — it quantifies how correlated our state uncertainty is with our measurement uncertainty. In the KF this was P⁻·Cᵀ; here it is computed directly from the sigma points without needing C or any Jacobian. Dividing by S(k) gives the Kalman Gain K, which has the same interpretation as in the KF: it is the optimal weight for the measurement correction.
The state correction follows the same intuition as the KF: the actual measured voltage y(k) minus the predicted voltage ŷ(k) forms the innovation, which K scales and adds to the predicted state. The covariance update subtracts the information gained from the measurement. Because both ŷ and S were computed through the nonlinear h (not linearised), the UKF’s correction is inherently more accurate than the EKF’s when the OCV curve has significant curvature — for example, near 20% or 90% SOC on an NMC cell.
UKF Tuning — Parameter Selection Guide
α: Controls sigma point spread (typically 10⁻³ ≤ α ≤ 1). Small α keeps points close to mean.
β: Encodes prior knowledge of distribution (β = 2 is optimal for Gaussian).
κ: Secondary scaling; typically κ = 0 or κ = 3−n.
Q: Process noise covariance — tune to reflect model uncertainty in SOC and V_RC.
R: Measurement noise covariance — set from voltage sensor noise specification.
✓ Advantages
- No Jacobian — works with any differentiable or even non-differentiable functions
- Third-order accuracy vs. EKF’s first-order
- Better performance on highly nonlinear OCV curves
- More stable convergence than EKF
- Directly handles state constraints (SOC ∈ [0,1])
✗ Limitations
- ~2–3× more computation than EKF per step
- More tuning parameters (α, β, κ)
- Still assumes Gaussian posterior — fails for highly non-Gaussian noise
- Not globally optimal for strongly nonlinear systems
Particle Filter
Core Idea
The Particle Filter represents the posterior probability distribution of the SOC as a set of weighted particles — discrete hypotheses about the current state. At each time step, particles are propagated through the model and re-weighted by how well they explain the new measurement. Particles that fit well survive; those that don’t are replaced. No Gaussian assumption. No linearity requirement.
Why PF for SOC?
- Handles non-Gaussian sensor noise (quantisation, impulse)
- Handles multimodal SOC uncertainty
- Arbitrary battery model — even lookup tables
- Robust to model mismatch and parameter uncertainty
- Suitable for SOH co-estimation with joint state-parameter PF
Bayesian Foundation
SIR Particle Filter Algorithm
The most common variant is Sequential Importance Resampling (SIR), also called Bootstrap PF:
How the Particle Filter Algorithm Works
The Particle Filter abandons the Gaussian assumption entirely. Instead of tracking a mean and covariance, it maintains a population of N hypotheses — called particles — each representing one possible state of the battery (SOC, V_RC). The population collectively represents the full probability distribution of the SOC, however shaped: unimodal, bimodal, skewed, or anything else. This is Sequential Monte Carlo estimation.
The core metaphor: Imagine 100 detectives, each holding a different theory about the battery’s current SOC. At every time step, each detective independently updates their theory using the current drawn. Then a new voltage measurement arrives. Detectives whose theory predicted a voltage close to the measured one are rewarded with a higher credibility score (weight). Those whose theory was far off have their score reduced toward zero. The final SOC estimate is the credibility-weighted average of all 100 theories. Detectives with near-zero credibility are eventually replaced (resampled) by copies of the most credible ones.
Initialisation: N particles are drawn from an initial distribution (e.g., uniform over [0,1] if SOC is unknown, or a narrow Gaussian around the measured OCV-based SOC). All start with equal weight 1/N.
Propagate → Weight → Estimate → Resample loop: Each particle is evolved through the nonlinear battery model with its own random noise sample. Weights are updated using the measurement likelihood — how well each particle’s predicted voltage matches the actual voltage. The SOC estimate is the weighted mean. The effective sample size N_eff is checked: if most weight has collapsed onto a few particles, resampling is triggered, drawing N new particles proportional to weights and resetting them to 1/N. This four-step loop repeats every BMS sample.
Why resampling matters: Without resampling, after many steps all weight concentrates on one particle (degeneracy), making the filter useless. But resampling too aggressively causes sample impoverishment — the particle cloud loses diversity and cannot track rapid SOC changes. The balance is maintained by only resampling when N_eff drops below N/2, and by ensuring the propagation step injects enough process noise to re-diversify particles after resampling. For SOC estimation, a well-tuned PF with N = 50–100 particles typically achieves accuracy comparable to or better than UKF, while being robust to outliers, current sensor drift, and even sudden changes in battery parameters during aging.
Each particle xᵢ is a complete hypothesis about the current battery state — a specific (SOC, V_RC) pair drawn randomly from the prior belief p(x₀). If the battery has just been fully charged, the prior might be a narrow Gaussian centred at SOC = 1.0. If the initial SOC is unknown, particles are drawn from a uniform distribution over [0, 1]. All N particles start with equal weight 1/N because we have no reason to prefer one hypothesis over another before seeing any data. With N = 100 particles, there are 100 different “candidate” SOC values simultaneously being tracked. The filter works by progressively weighting down incorrect hypotheses and concentrating probability mass on the correct one.
Every particle is evolved forward using the battery model f — the same Thevenin equations as EKF/UKF. However, each particle receives its own independently drawn process noise sample wᵢ from p(w). This is the Monte Carlo principle in action: by drawing different noise realisations for each particle, the set collectively represents the full spread of where the true state could be after the time update. Crucially, p(w) can be any distribution — uniform, Laplacian, bimodal — not just Gaussian. This is the first place where the PF surpasses all KF variants: it handles non-Gaussian process noise naturally by sampling from it.
For every particle, we ask: “if the true SOC were xᵢ(k), how likely is it that the battery would produce the measured terminal voltage y(k)?” This is evaluated using the likelihood function p(y|x). For Gaussian sensor noise with variance σ²: p(y|xᵢ) = exp(−(y − h(xᵢ))² / 2σ²) / √(2πσ²), where h(xᵢ) = OCV(SOCᵢ) − R₀·I − V_RC_i. Particles whose predicted voltage closely matches the actual measurement get high likelihood and therefore high weight. Particles that predict a wildly different voltage get a weight near zero — they are being “voted down” by the data. This step is entirely nonlinear and requires no Jacobian.
The unnormalised weights w̃ᵢ are divided by their total sum to ensure the weights form a valid probability distribution (Σwᵢ = 1). After normalisation, each wᵢ represents the relative probability that particle i contains the true state. A well-performing filter at this point will have a few particles with high weights (near the true SOC) and many with weights approaching zero (wrong SOC hypotheses). The weighted mean Σwᵢ·xᵢ is the SOC estimate — not a single particle, but the centre of mass of all particles weighted by their evidence.
The SOC estimate is the weighted average of all N particle states. High-weight particles (those consistent with the latest voltage measurement) pull the estimate toward their SOC value; low-weight particles barely contribute. This is a direct approximation of the posterior mean E[x|y(1:k)]. Unlike KF variants, the PF can represent any posterior shape — if particles cluster in two groups (bimodal distribution, possible after sensor loss), the weighted mean correctly sits between them, and the variance P(k) reflects the genuine multi-hypothesis uncertainty.
The variance P(k) measures how spread out the particle cloud is. A narrow cluster (small P) means the filter is confident in the SOC estimate. A wide cloud (large P) means high uncertainty — perhaps because no measurement was available for several seconds, or the voltage measurement was ambiguous. Unlike the KF’s covariance matrix which is propagated analytically (and can become inconsistent), the PF’s uncertainty is always derived directly from the particle distribution, making it inherently self-consistent.
Over time, a catastrophic phenomenon called particle degeneracy occurs: nearly all weight concentrates on a single particle, while the rest carry negligible weight. The effective sample size N_eff measures how many particles are “usefully contributing” — it ranges from 1 (fully degenerate: only one particle matters) to N (all particles equally weighted, ideal). When N_eff drops below a threshold (typically N/2), the filter is wasting computation on irrelevant particles and its estimate becomes unreliable. Resampling is triggered to correct this.
Resampling draws N new particles from the current weighted set, where each particle’s probability of being selected equals its weight wᵢ. High-weight particles are copied multiple times; low-weight particles are likely discarded entirely. The result is N particles that are all equally weighted (1/N) but are concentrated near where the high-weight particles were. Systematic resampling — using a single random number and a regular grid — is preferred over simple multinomial resampling because it has lower variance and avoids duplicating the same particle too many times. After resampling, the particle diversity is restored and the algorithm continues. However, repeated resampling can cause sample impoverishment — loss of diversity when too many copies of the same particle are made — which is countered by ensuring adequate process noise in step P-1.
Likelihood Function Design
The weight update uses the measurement likelihood p(y|x). For Gaussian voltage noise:
p(y(k)|xᵢ(k)) = exp(−(y−h(xᵢ))² / 2σ²) / √(2πσ²)
For robust estimation with sensor outliers, use a heavy-tailed likelihood (Student-t or Huber) instead of Gaussian.
Advanced: Auxiliary PF & Rao-Blackwellised PF
Auxiliary PF: Resamples before propagation, reducing degeneracy. Better for highly informative measurements.
Rao-Blackwellised PF: Marginalises the linear sub-state analytically (e.g., V_RC via KF), only particles the nonlinear state (SOC). Greatly reduces N needed.
✓ Advantages
- No Gaussian assumption on noise or state
- No linearity requirement
- Handles multimodal distributions
- Works with any battery model (even black-box lookup tables)
- Theoretically asymptotically optimal as N→∞
- Natural framework for joint SOC+SOH estimation
✗ Limitations
- Computationally expensive — O(N) per step
- Particle degeneracy / sample impoverishment
- Hard to implement efficiently on embedded systems
- Requires careful tuning of N and resampling strategy
- Performance degrades in high-dimensional state spaces
Side-by-Side Comparison
| Property | Kalman Filter | Extended KF | Unscented KF | Particle Filter |
|---|---|---|---|---|
| System type | Linear only | Weakly nonlinear | Strongly nonlinear | Any |
| Noise assumption | Gaussian required | Gaussian required | Gaussian assumed | None |
| Accuracy | 1st-order | 1st-order | 3rd-order | Asymptotic |
| Jacobian needed | No | Yes | No | No |
| Computation | Very low | Low | Medium | High |
| SOC accuracy (NMC) | Poor | 1–3% | 0.5–2% | 0.5–2% |
| SOC accuracy (LFP) | Poor | 2–5% | 1–3% | 1–2% |
| Tuning complexity | Low (Q, R) | Low (Q, R) | Medium (α,β,κ,Q,R) | High (N, resample) |
| MCU feasibility | Easy | Easy | Moderate | Challenging |
| BMS use case | Seldom (linear approx only) | Industry standard | High-accuracy BMS | Research, SOC+SOH joint |
Decision Flowchart — Which Filter to Use?
Implementation Tips for BMS Engineers
Noise Covariance Tuning
- Q (process noise): reflects uncertainty in the battery model. Start with
Q = diag([10⁻⁴, 10⁻⁶])for [SOC, V_RC] and tune. - R (measurement noise): set from voltage sensor specification. A 1mV RMS sensor gives
R = 10⁻⁶V². - Adaptive Q/R estimation (e.g., Sage-Husa algorithm) improves robustness across aging and temperature.
SOC Bounds Enforcement
- KF/EKF/UKF: add a hard clip after state update —
SOC = clamp(SOC, 0, 1). - For EKF, the clipping violates the Gaussian assumption; consider constrained KF variants.
- PF naturally handles constraints by setting particle weights to zero outside [0,1].
- Never allow SOC to drift below 0% or above 100% in state vector.
Initialisation
- Best: measure OCV at rest to initialise SOC before drive cycle.
- EKF/UKF: set
P₀large (e.g., 0.1) to allow rapid correction from initial uncertainty. - PF: draw initial particles from a wide uniform distribution over [0,1] if rest OCV unavailable.
Computation Budget (embedded)
- EKF for a 2-state Thevenin model: ~50 FLOPs per step — trivially fast on any MCU.
- UKF (n=2): 5 sigma points, ~300 FLOPs per step — fine on Cortex-M4.
- PF (N=100 particles): ~10,000 FLOPs per step — requires Cortex-M7, DSP, or FPGA for 100Hz BMS cycles.
- Consider N=20–50 particles with a good resampling strategy as a compromise.
