Difficulty: Intermediate | Prerequisites: Part 1 of these notes, basic circuit theory (Ohm's law, KCL, KVL)
The OCV-R model is the simplest equivalent circuit for a battery: an OCV source in series with an internal resistance. It predicts terminal voltage under constant discharge and pulse current, and it is the foundation for every more complex battery model in this course. Coulomb counting tracks SOC by integrating current, and the OCV curve can be parameterised with either a polynomial fit or a nonlinear function using least-squares methods.
OCV-R model
The simplest equivalent circuit model for a battery: an open-circuit voltage source (OCV) in series with a single lumped internal resistance (R_int). Think of it as the battery reduced to two components.
Kirchhoff's Current Law (KCL)
The sum of all currents entering a node equals zero: Sigma(i_k) = 0. In simple terms, charge cannot pile up at a junction.
Kirchhoff's Voltage Law (KVL)
The sum of all voltages around any closed loop equals zero: Sigma(e_i) = 0. In simple terms, energy is conserved around every loop in the circuit.
Potentiostatic operation
Applying a fixed voltage across the battery terminals and observing the resulting current. This is the mode used during the constant-voltage phase of CC-CV charging.
Galvanostatic operation (constant current)
Applying a fixed current through the battery and observing the resulting terminal voltage. This is the mode used during the constant-current phase of CC-CV charging and during standard discharge tests.
Pulse current test
A short burst of current applied to a battery at a known SOC, used to estimate internal resistance from the instantaneous voltage drop. The resistance is calculated as R_int = delta_V / delta_I.
Polynomial OCV fit
Approximating the OCV-vs-SOC curve as a polynomial: V_hat = alpha_0 + alpha_1z + alpha_2z^2 + ... + alpha_n*z^n, solved via least-squares regression.
Nonlinear OCV function
A parametric curve-fit of the form V_oc(z) = V_0 + alpha*(1 - exp(-betaz)) + gammaz + zeta*(1 - exp(-epsilon/(1-z))), with tunable parameters fitted using lsqcurvefit or similar optimisers.
Power balance
In a circuit, total power supplied by all sources equals total power consumed by all resistive elements. Used as a cross-check on KCL/KVL solutions.
Circuit elements
Resistance (R): V = IR (Ohm's law). Energy is dissipated as heat.
Capacitance (C): i = C dV/dt. Stores energy in an electric field.
Inductance (L): V = L di/dt. Stores energy in a magnetic field.
Kirchhoff's Current Law (KCL)
At any node, the sum of currents entering equals the sum leaving. Convention: current approaching a node is positive.
Kirchhoff's Voltage Law (KVL)
Around any closed loop, the sum of all voltage rises and drops equals zero.
Procedure for applying KVL:
Choose an arbitrary loop direction (e.g. clockwise)
Define the current direction for each branch
A voltage source is positive if the loop traverses it from minus to plus
A voltage across a passive element is positive if the element's current direction opposes the loop direction
Worked example from lecture (two-loop circuit):
Given two voltage sources E_1 and E_2 with resistors R_1, R_2, and R, and three currents i_1, i_2, i_3:
Loop 1: -i_1R_1 + E_1 - E_2 - i_3R_2 = 0
Loop 2: E_2 - i_2R + i_3R_2 = 0
KCL: i_1 - i_3 - i_2 = 0
Three unknowns, three equations. Solve for i_1, i_2, i_3.
Result: i_1 = i_2 + i_3, or equivalently (E_1 - V_0)/R_1 = V_0/R + (V_0 - E_2)/R_2
Power balance
If current flows through a source from minus to plus, that source supplies power (P = E * i). Total power supplied must equal total power consumed (P_supplied = P_consumed = sum of i^2 * R across all resistors). This serves as a check on your KCL/KVL solution.
Potentiostatic operation
Given a fixed terminal voltage V_0 applied across a battery (modelled as E_1 in series with R_1), the resulting current is I_1 = (V_0 - E_1) / R_1. This applies to the CV phase of battery charging.
Circuit: A voltage source labelled OCV(z) in series with a single resistor R_int. The terminal voltage V_t is measured across the external terminals.
Math model:
V_t = OCV(z) - I * R_int (during discharge, where I > 0)
V_t = OCV(z) + I * R_int (during charge, where I < 0 by convention, so the product adds to OCV)
More compactly, using the convention that positive I means discharge:
V_t = OCV(z) - I * R_int
The SOC evolves according to Coulomb counting:
z_dot = -1 / (3600 * C_n) * I
where C_n is the nominal capacity in Ah and the 3600 converts hours to seconds.
Behaviour:
At rest (I = 0): V_t = OCV(z). The terminal voltage sits on the OCV curve.
During discharge (I > 0): V_t drops below OCV by an amount I * R_int.
During charge (I < 0): V_t rises above OCV by the same mechanism.
The voltage offset is instantaneous and proportional to current. There is no time-dependent transient in this model (that requires adding RC elements, covered in later lectures).
This is the simplest possible battery model, yet it captures the two most important first-order effects: the dependence of voltage on SOC (through OCV) and the immediate resistive drop under load.
When a constant current I is applied:
SOC decreases linearly: z(t) = z_0 - It / (3600C_n)
OCV(z) decreases as z decreases (following the OCV curve shape)
Terminal voltage: V_t(t) = OCV(z(t)) - I*R_int
The terminal voltage curve during constant discharge is the OCV curve shifted downward by the constant offset I*R_int. At higher discharge rates, the offset is larger, so the voltage curve sits lower.
Capacity estimation from constant discharge:
Discharge ends when V_t hits V_min. Because V_t = OCV - I*R_int, higher currents cause V_t to reach V_min at a higher SOC than lower currents. This means the usable (apparent) capacity decreases at higher C-rates, even though the total stored charge has not changed.
The lecture's reference data (Gao, Liu, Dougal, IEEE 2002) shows voltage vs. state of discharge at currents of 0.28 A, 0.7 A, 1.0 A, 1.4 A, and 2.8 A. At higher currents the curves sit lower and the battery appears to have less capacity.
Real-world context. This is exactly what you see on a Panasonic NCR18650A datasheet's "Discharge Characteristics (by rate of discharge)" plot. The OCV-R model qualitatively reproduces this rate-dependent behaviour.
A pulse test applies a short burst of current (typically a few seconds to a few minutes) at a known SOC, then returns to rest.
What happens:
Before the pulse: V_t = OCV(z) (battery at rest)
Pulse applied (current I starts): V_t drops instantaneously by I * R_int
During the pulse: V_t stays roughly constant (SOC barely changes in a short pulse), possibly drifting slightly
Pulse removed: V_t jumps back up by I * R_int, returning to approximately OCV(z)
Estimating internal resistance:
R_int = delta_V / I = (OCV - V_t_during_pulse) / I
Because the pulse is short, SOC does not change appreciably, so the OCV before and after the pulse is essentially the same. The instantaneous voltage jump is entirely due to R_int.
Why this matters: Pulse tests are the standard experimental method for extracting R_int at various SOC and temperature operating points. In practice, R_int is not constant but varies with SOC and temperature. The OCV-R model treats it as constant for simplicity.
Coulomb counting equation:
z_dot = -1 / (3600 * C_n) * I
where z is SOC normalised to (0, 1), C_n is the nominal capacity in Ah, and I is positive for discharge. Integrating: z(t) = z(0) - (1 / (3600*C_n)) * integral of I dt.
This is simply an integrator. If you know the starting SOC and can measure current, you can track SOC over time.
Nonlinear OCV function:
V_oc(z) = V_0 + alpha*(1 - exp(-betaz)) + gammaz + zeta*(1 - exp(-epsilon/(1-z)))
The parameters V_0, alpha, beta, gamma, zeta, and epsilon are tunable and are fitted to experimental data. Each term captures a different feature of the OCV curve:
V_0: baseline voltage offset
alpha*(1 - exp(-beta*z)): captures the steep rise at low SOC (near empty)
gamma*z: the roughly linear middle portion of the curve
zeta*(1 - exp(-epsilon/(1-z))): captures the steep drop near full charge (z approaching 1)
This functional form is used in the Simscape (Mathworks) battery block and in many published models (Hu, Yurkovich, Guezennec, Yurkovich, Journal of Power Sources, 2011).
Fitting the model: Use MATLAB's lsqcurvefit to find the parameter values that minimise the sum of squared differences between the model's predicted OCV and the measured OCV data.
Key insight: At very low currents (C/10 or lower), the resistive drop I*R_int is negligibly small, so the measured terminal voltage approximates the true OCV. This gives you a dataset of V vs z that you can fit.
Polynomial approach:
Assemble the measured data into a matrix equation:
V_bar = Z_bar * A
where V_bar is the column vector of measured voltages [V_hat(0), V_hat(1), ..., V_hat(k)]^T, Z_bar is the Vandermonde-style matrix with rows [1, z[k], z[k]^2, ..., z[k]^n], and A is the column vector of polynomial coefficients [alpha_0, alpha_1, ..., alpha_n]^T.
Solve using MATLAB's backslash operator: A = Z_bar \ V_bar, which computes the least-squares solution (equivalent to inv(Z_bar' * Z_bar) * Z_bar' * V_bar but numerically more stable).
Nonlinear approach:
Use MATLAB's lsqcurvefit with the parametric OCV function from the previous section. Provide initial guesses for V_0, alpha, beta, gamma, zeta, epsilon, and the solver iteratively minimises the residual.
Practical notes:
Polynomial order: too low and you miss the curve shape; too high and you overfit (wiggles between data points). Typically 6th to 10th order works well for most chemistries.
The nonlinear function has fewer parameters but each has a physical interpretation, making it more robust for extrapolation.
Both methods are covered in HW2.
For high-power applications (electric vehicles, grid storage), individual cells are arranged in series and parallel to meet voltage and energy requirements.
Series configuration:
Cells in series add their voltages. The pack voltage is:
V_pack = n_s * V_nom
where n_s is the number of cells in series and V_nom is the nominal cell voltage. You select n_s to match the voltage required by the power electronics (inverter, motor controller).
Parallel configuration:
Cells in parallel add their charge capacities. The pack energy is:
E = (n_p * Q_cap) * (n_s * V_nom)
where n_p is the number of parallel strings and Q_cap is the charge capacity of a single cell. You select n_p to achieve the desired pack energy.
Real-world examples from the lecture:
Tesla Model S: 7,104 cylindrical cells (Panasonic) in 16 modules, 85 kWh
Nissan Leaf: 192 pouch cells (NEC) in 48 modules, 24 kWh
Chevy Volt: 288 prismatic cells (LG Chem) in 9 modules, 16.5 kWh
Other design considerations: packaging, thermal management, modularity across vehicle platforms, cell balancing, and safety (fusing, contactors, BMS).
Students often think the OCV-R model captures transient (time-dependent) voltage behaviour. It does not. When current changes, the voltage change is instantaneous in this model. The slow voltage relaxation you see in real batteries requires RC elements, which are added in later lectures.
A common mistake is to forget the sign convention for current. In most battery modelling, positive I means discharge. Mixing this up flips the voltage drop direction and gives nonsensical results.
Students sometimes assume internal resistance is constant. In reality R_int depends on SOC, temperature, and the age of the cell. The OCV-R model uses a constant R_int as a simplification.
When fitting the OCV curve with a polynomial, students sometimes use too high an order and overfit. The resulting curve may oscillate wildly between data points while passing through each one perfectly. Cross-validation or a held-out test set catches this.
⚠️ Be able to write V_t = OCV(z) - I*R_int and explain each term. This equation is the backbone of the first several homework assignments.
⚠️ Derive the terminal voltage expression for both constant-current and constant-load discharge modes (HW1, Problem 3).
⚠️ Know how to estimate R_int from a pulse test: R = delta_V / delta_I.
⚠️ Be comfortable setting up the Vandermonde matrix for polynomial OCV fitting and solving with MATLAB's backslash operator (HW2).
⚠️ Understand why apparent capacity decreases at higher discharge rates, even though stored charge is unchanged.
⚠️ Be able to calculate V_pack and E_pack from n_s, n_p, V_nom, and Q_cap.
True or False: In the OCV-R model, terminal voltage during discharge is always lower than OCV at the same SOC. True.
Fill in the blank: R_int can be estimated from a pulse test as R_int = ______ / ______. (delta_V / delta_I)
True or False: Coulomb counting requires measuring voltage to track SOC. False. It requires measuring current and integrating over time.
Fill in the blank: For a battery pack with 96 cells in series, each at 3.6 V nominal, V_pack = ______ V. (345.6 V)
True or False: A 12th-order polynomial is always better than a 6th-order polynomial for fitting OCV data. False. Higher orders risk overfitting.
Q: A battery has OCV(z) = V^0 * (2z - z^2), R_int = 0.1 ohm, and total capacity C = 3 Ah. Write the expression for terminal voltage V_t during constant-current discharge at I = 5 A. At what SOC does V_t reach zero?
A: V_t = V^0*(2z - z^2) - 50.1 = V^0(2z - z^2) - 0.5. Setting V_t = 0: V^0*(2z - z^2) = 0.5, then solve for z given V^0. With V^0 = 3.6 V: 3.6*(2z - z^2) = 0.5, giving z^2 - 2z + 0.139 = 0. Using the quadratic formula: z = (2 - sqrt(4 - 0.556))/2 ≈ 0.072.
Q: Explain the difference between potentiostatic and galvanostatic battery operation.
A: Potentiostatic operation fixes the terminal voltage and lets the current vary (the CV phase of charging). Galvanostatic operation fixes the current and lets the terminal voltage vary (the CC phase of charging, and standard discharge tests).
Q: You measure a battery's OCV at rest as 3.85 V, then apply a 2 A discharge pulse and observe the terminal voltage drop to 3.65 V. What is the internal resistance?
A: R_int = (3.85 - 3.65) / 2 = 0.20 / 2 = 0.1 ohm.
Q: A pack needs 400 V nominal and 60 kWh of energy. Each cell is 3.7 V nominal with 3.0 Ah capacity. How many cells in series and how many parallel strings are needed?
A: n_s = 400 / 3.7 ≈ 108 cells in series (round to nearest integer). Energy per string = 108 * 3.7 * 3.0 = 1198.8 Wh ≈ 1.2 kWh. n_p = 60,000 / 1198.8 ≈ 50 parallel strings. Total cells = 108 * 50 = 5,400.
Q: Why does the OCV-R model predict an instantaneous voltage jump when current changes, while real batteries show a gradual transition?
A: The OCV-R model contains only a resistor, which responds instantaneously (V = IR with no time dependence). Real batteries have charge-transfer and diffusion processes that behave like RC circuits with time constants. These are captured by adding one or more RC pairs in series, which is the next level of model complexity.
The OCV-R model is the starting point for all equivalent circuit models in ME565. Later lectures add RC pairs (for transient behaviour), thermal coupling (resistance changes with temperature), and ageing effects (capacity fade, resistance growth). Every one of those extensions builds directly on V_t = OCV(z) - I*R_int.
The Coulomb counting equation z_dot = -(1/3600C_n)*I will reappear as the state equation in Kalman filter-based SOC estimators. Understanding it here makes the state-space formulation in later lectures straightforward.
The pack design principles (series for voltage, parallel for capacity) connect to the battery management system (BMS) topics later in the course, particularly cell balancing and fault detection.
OCV-R model, equivalent circuit model, internal resistance, terminal voltage, Kirchhoff's current law, KCL, Kirchhoff's voltage law, KVL, Coulomb counting, state of charge estimation, SOC, polynomial OCV fit, Vandermonde matrix, lsqcurvefit, nonlinear OCV model, pulse test, battery resistance estimation, constant current discharge, constant load discharge, potentiostatic, galvanostatic, CC-CV charging, battery pack design, series parallel cells, V_pack, energy capacity, Tesla Model S battery, Nissan Leaf battery, Chevy Volt battery, ME565, battery control and systems, University of Michigan, Simscape battery block