Skip to content

BESS Subsystem Simulation Model (AI / Code Generation Version)

This document specifies the equivalent mathematical models for the BESS subsystem using formal notation for automated code generation. Targets: Python (NumPy), C/C++ (embedded RPi), MATLAB/Simulink.

Sign convention: $I_b > 0$ = Charging, $I_b < 0$ = Discharging. $P_{req} > 0$ = Charge request, $P_{req} < 0$ = Discharge request.


Simulation Loop (Top-Level Pseudocode)

The following shows the recommended execution order at each discrete time step $k$ with step size $\Delta t$:

# ─── Initialization (run once before loop) ──────────────────────────
SoC   = SoC_initial        # e.g., 0.5
Vc1   = 0.0
Vc2   = 0.0
Tb    = 25.0               # degrees Celsius
Pout  = 0.0
Qout  = 0.0
SoH   = 1.0
SoR   = 1.0
Vdc_pcs_prev = V_BESS_nom  # used for algebraic loop decoupling

# ─── Per-step loop ───────────────────────────────────────────────────
for k in range(N_steps):

    # 1. Interpolate ECM parameters from CSV at current SoC
    OCV, R0, R1, C1, R2, C2 = interpolate_csv(SoC)
    R0_eff = R0 * SoR       # apply aging resistance scale

    # 2. BMS: compute power limits
    I_lim_chg  = min(I_max_charge,   (V_cell_max - OCV) / R0_eff)
    I_lim_dis  = min(I_max_discharge, (OCV - V_cell_min) / R0_eff)
    P_lim_chg  = I_lim_chg  * Vb
    P_lim_dis  = I_lim_dis  * Vb

    # 3. PCS: limit and track setpoint
    Preq_lim = clamp(Preq, -P_lim_dis, +P_lim_chg)
    Preq_lim = clamp(Preq_lim, -S_max, +S_max)
    Pout = Pout + dt * (Preq_lim - Pout) / tau_p
    Qout = Qout + dt * (Qreq_lim - Qout) / tau_q

    # 4. PCS: DC/AC power balance (use Vdc_pcs from previous step)
    if Pout >= 0:   # charging (rectifier)
        Pdc_pcs = Pout * eta_pcs
    else:           # discharging (inverter)
        Pdc_pcs = Pout / eta_pcs
    Ib = Pdc_pcs / Vdc_pcs_prev

    # 5. Battery Array: update states
    SoC = clamp(SoC + (Ib * dt / Q_cap), 0.0, 1.0)
    Vc1 = Vc1 + dt * (-(Vc1 / (R1 * C1)) + (Ib / C1))
    Vc2 = Vc2 + dt * (-(Vc2 / (R2 * C2)) + (Ib / C2))
    Vb  = OCV + Vc1 + Vc2 + (Ib * R0_eff)

    # 6. DC Line: compute PCS DC terminal voltage
    Vdc_pcs = Vb + Ib * R_dc_line
    Vdc_pcs_prev = Vdc_pcs   # store for next step decoupling

    # 7. Thermal model
    P_heat = Ib**2 * R0_eff + Vc1**2 / R1 + Vc2**2 / R2
    Tb = Tb + dt * (1 / (m_cp)) * (P_heat - (Tb - T_amb) / R_th)

    # 8. BMS: alarms
    check_alarms(SoC, Vb, Tb, N_series, V_cell_min, V_cell_max, T_max, ...)

    # 9. SoH / SoR: update per cycle (outside per-step, at cycle boundary)
    # SoH -= SoH_degrad_per_cycle
    # SoR  = 1.0 + (1.0 - SoH) * resistance_aging_factor

1. Battery Array Model

1.1 Second-Order LMFP Equivalent Circuit Model

Reference Data: Parameters $R_0, R_1, C_1, R_2, C_2$, and $OCV(SoC)$ are sourced from HPPC experimental data. - Dataset: lmfp_2nd_order_ecm_parameters.csv - Note: $OCV$ for LMFP features a two-plateau structure due to the Manganese addition.

Interpolation (linear, at each step):

f(SoC) = f_{low} + \frac{SoC - SoC_{low}}{SoC_{high} - SoC_{low}} \cdot (f_{high} - f_{low})
Apply for: $OCV, R_0, R_1, C_1, R_2, C_2$. Apply aging: $R_{0,eff} = R_0 \cdot SoR$.

Variables & States: - $SoC$: State of Charge (State, $0.0 \dots 1.0$). Initial: 0.5 - $V_{c1}$: Voltage across first RC pair (State, Volts). Initial: 0.0 - $V_{c2}$: Voltage across second RC pair (State, Volts). Initial: 0.0 - $I_{b}$: Battery terminal current (Input, Amps). Positive for charge. - $V_{b}$: Battery terminal voltage (Output, Volts)

Parameters: - $Q_{cap}$: Total array capacity (Amp-seconds). Default: 360,000 As (100 Ah) - $OCV(SoC)$: Open Circuit Voltage. Lookup + interpolate from CSV. - $R_0, R_1, R_2$: Resistances ($\Omega$). Lookup + interpolate from CSV. - $C_1, C_2$: Capacitances (Farads). Lookup + interpolate from CSV. - $I_{max_charge}$: Max continuous charge current (Amps). Default: 100 A - $I_{max_discharge}$: Max continuous discharge current (Amps). Default: 100 A

Discrete State Equations (implement at each step $k$):

SoC[k] = \mathrm{clamp}\!\left(SoC[k-1] + \frac{I_{b}[k] \cdot \Delta t}{Q_{cap}},\ 0,\ 1\right)
V_{c1}[k] = V_{c1}[k-1] + \Delta t \left( -\frac{V_{c1}[k-1]}{R_1 C_1} + \frac{I_{b}[k]}{C_1} \right)
V_{c2}[k] = V_{c2}[k-1] + \Delta t \left( -\frac{V_{c2}[k-1]}{R_2 C_2} + \frac{I_{b}[k]}{C_2} \right)

Output Equation:

V_{b} = OCV(SoC) + V_{c1} + V_{c2} + I_{b} \cdot R_{0,eff}


1.2 Simplified Thermal Model

Variables & States: - $T_{b}$: Battery temperature (State, $^\circ C$). Initial: 25.0 C - $T_{amb}$: Ambient temperature (Input). Default: 25.0 C

Parameters: - $m \cdot c_p$: Total heat capacity (J/$^\circ C$). Default: 10,000,000 - $R_{th}$: Thermal resistance to ambient ($^\circ C$/W). Default: 0.1

Heat Generation:

P_{heat} = I_{b}^2 R_{0,eff} + \frac{V_{c1}^2}{R_1} + \frac{V_{c2}^2}{R_2}

Discrete Temperature Update:

T_{b}[k] = T_{b}[k-1] + \Delta t \cdot \frac{1}{m \cdot c_p} \left[ P_{heat} - \frac{T_{b}[k-1] - T_{amb}}{R_{th}} \right]


2. BESS DC Line

Purely resistive cable between Battery Array and PCS.

  • $R_{dc_line}$: Lumped cable resistance. Default: 0.005 $\Omega$
V_{dc\_pcs} = V_{b} + I_{b} \cdot R_{dc\_line}

(During charging $I_b > 0$, so $V_{dc_pcs} > V_b$. During discharging $I_b < 0$, so $V_{dc_pcs} < V_b$.)


3. BESS AC Line

Phasor average model of the cable between PCS and PCC grid bus.

Parameters: - $V_{ac_bus}$: Grid bus RMS voltage. Default: 400 V - $R_{ac_line}, L_{ac_line}$: Line R and L. Defaults: 0.01 $\Omega$, 0.0001 H - $X_{ac_line} = \omega L_{ac_line}$ where $\omega = 2\pi \cdot 50\ \text{Hz}$. Default: $\approx 0.0314\ \Omega$ - $\delta$: PCS–bus phase angle (radians). Controlled variable.

P_{ac\_line} = \frac{V_{ac\_pcs} \cdot V_{ac\_bus}}{X_{ac\_line}} \sin(\delta)
Q_{ac\_line} = \frac{V_{ac\_pcs}^2 - V_{ac\_pcs} \cdot V_{ac\_bus} \cos(\delta)}{X_{ac\_line}}


4. BESS PCS (Power Conversion System)

First-order lag model of the inverter/rectifier control loop.

Variables & States: - $P_{req}, Q_{req}$: EMS power setpoints (W, VAr). Positive = Charge. - $P_{out}, Q_{out}$: Actual PCS output power states. Initial: 0.0

Parameters: - $\tau_p, \tau_q$: Response time constants (s). Default: 0.05 s - $\eta_{pcs}$: Conversion efficiency. Default: 0.98 - $S_{max}$: Apparent power limit (VA). Default: 1,000,000 VA

Step 1 — Clamp setpoint to BMS limits:

P_{req\_limited} = \mathrm{clamp}(P_{req},\ -P_{limit\_discharge},\ +P_{limit\_charge})
P_{req\_limited} = \mathrm{clamp}(P_{req\_limited},\ -S_{max},\ +S_{max})

Step 2 — Discrete power tracking:

P_{out}[k] = P_{out}[k-1] + \Delta t \cdot \frac{P_{req\_limited} - P_{out}[k-1]}{\tau_p}
Q_{out}[k] = Q_{out}[k-1] + \Delta t \cdot \frac{Q_{req\_limited} - Q_{out}[k-1]}{\tau_q}

Step 3 — DC/AC power balance:

P_{dc\_pcs} = \begin{cases}
    P_{out} \cdot \eta_{pcs} & \text{if } P_{out} \geq 0\ \text{(charge / rectifier)} \\
    P_{out}\ /\ \eta_{pcs}  & \text{if } P_{out} < 0\ \text{(discharge / inverter)}
\end{cases}
I_{b} = \frac{P_{dc\_pcs}}{V_{dc\_pcs}[k-1]}
(Use $V_{dc_pcs}[k-1]$ from the previous step to avoid an algebraic feedback loop.)


5. BMS (Battery Management System) Signals

5.1 Power Limits

Current limits (structural + electrochemical voltage margin):

I_{limit\_charge}   = \min\!\left(I_{max\_charge},\ \frac{V_{cell\_max} - OCV(SoC)}{R_{0,eff}}\right)
I_{limit\_discharge} = \min\!\left(I_{max\_discharge},\ \frac{OCV(SoC) - V_{cell\_min}}{R_{0,eff}}\right)

Power limits:

P_{limit\_charge}   = I_{limit\_charge}   \cdot V_b
P_{limit\_discharge} = I_{limit\_discharge} \cdot V_b

5.2 State of Health and State of Resistance

Updated once per full charge/discharge cycle (not per time step):

SoH_{n+1} = SoH_{n} - \delta_{SoH}
SoR = 1.0 + (1.0 - SoH) \cdot k_{aging}

Parameters: - $\delta_{SoH}$: Capacity fade per cycle. Typical LMFP: 0.0002 (0.02%/cycle) - $k_{aging}$: Resistance aging factor. Default: 0.5

Application: At each step, compute effective resistance as $R_{0,eff} = R_0 \cdot SoR$.

5.3 Calculated Signals

  • SoC: From Battery Array state.
  • SoH: Updated per cycle.
  • SoR: Updated per cycle, drives $R_{0,eff}$.
  • P_limit_charge, P_limit_discharge: Updated each step, sent to PCS.

5.4 Alarms

IF SoC < SoC_min_threshold   THEN Alarm_Min_SoC = TRUE        // Default: 0.1
IF SoC > SoC_max_threshold   THEN Alarm_Max_SoC = TRUE        // Default: 0.9
IF (V_b / N_s) < V_cell_min  THEN Alarm_Min_CellVolt = TRUE   // Default: 2.8 V
IF (V_b / N_s) > V_cell_max  THEN Alarm_Max_CellVolt = TRUE   // Default: 4.0 V
IF T_b > T_max               THEN Alarm_Max_Temp = TRUE       // Default: 60 C

6. Model Calibratable Parameters

6.1 Battery Scaling Matrix

Specify any two of the three; the third is auto-computed:

  1. $V_{BESS_nom}$: Nominal DC bus voltage. Default: 1000 V
  2. $V_{cell_nom}$: Nominal cell voltage (LMFP $\approx 3.8$ V). Default: 3.8 V
  3. $N_s$: Cells in series. Default: 263

Scaling rules from per-cell CSV to array:

Quantity Array Value
OCV, Vb $\times N_s$
$R_0, R_1, R_2$ $\times N_s$
$C_1, C_2$ $\div N_s$
$Q_{cap}$ Ah $\times$ 3600 $\times$ parallel strings

6.2 Initial States

Variable Default
$SoC_0$ 0.5
$SoH_0$ 1.0
$SoR_0$ 1.0
$T_{b,0}$ 25.0 °C
$V_{c1,0}, V_{c2,0}$ 0.0 V
$P_{out,0}, Q_{out,0}$ 0.0 W

6.3 Runtime Fault Flags

  • Fault_PCS_Trip: Set $P_{out} = Q_{out} = 0$ (trip contactor).
  • Fault_BMS_SensorLoss: Override SoC or $T_b$ with stale/incorrect value.
  • Fault_ShortCircuit: Set $V_{ac_bus} = 0$ (FRT / grid collapse test).

7. PCS Calibratable Parameters

Parameter Symbol Default
Max apparent power $S_{max}$ 1,000,000 VA
Efficiency $\eta_{pcs}$ 0.98
Active power time constant $\tau_p$ 0.05 s
Reactive power time constant $\tau_q$ 0.05 s
Min DC voltage trip $V_{dc_min}$ 850 V
Max DC voltage trip $V_{dc_max}$ 1200 V