111 lines
3.9 KiB
Markdown
111 lines
3.9 KiB
Markdown
SIM_API_v1:
|
|
functions:
|
|
params_to_constitutive:
|
|
description: "Computes state-dependent battery parameters with guards."
|
|
inputs:
|
|
x: "[z, v_p, T_b, S, w]"
|
|
params: "MODEL_SPEC.parameters"
|
|
outputs:
|
|
V_oc: "Open-circuit voltage [V]"
|
|
R0: "Internal resistance [Ohm]"
|
|
Q_eff: "Effective capacity [Ah]"
|
|
logic:
|
|
- "z_eff = max(z, params.z_min)"
|
|
- "V_oc = params.E0 - params.K * (1/z_eff - 1) + params.A * exp(-params.B * (1 - z))"
|
|
- "R0 = params.R_ref * exp((params.E_a / params.R_g) * (1/T_b - 1/params.T_ref)) * (1 + params.eta_R * (1 - S))"
|
|
- "Q_eff = max(params.Q_nom * S * (1 - params.alpha_Q * (params.T_ref - T_b)), params.Q_eff_floor)"
|
|
|
|
power_mapping:
|
|
description: "Maps user inputs and radio state to total power demand."
|
|
inputs:
|
|
u: "[L, C, N, Ψ, T_a]"
|
|
x: "[z, v_p, T_b, S, w]"
|
|
params: "MODEL_SPEC.parameters"
|
|
outputs:
|
|
P_tot: "Total power [W]"
|
|
logic:
|
|
- "P_scr = params.P_scr0 + params.k_L * L^params.gamma"
|
|
- "P_cpu = params.P_cpu0 + params.k_C * C^params.eta"
|
|
- "P_net = params.P_net0 + params.k_N * N / (Ψ + params.epsilon)^params.kappa + params.k_tail * w"
|
|
- "P_tot = params.P_bg + P_scr + P_cpu + P_net"
|
|
|
|
current_cpl:
|
|
description: "Solves the quadratic CPL equation for current."
|
|
inputs:
|
|
V_oc: "[V]"
|
|
v_p: "[V]"
|
|
R0: "[Ohm]"
|
|
P_tot: "[W]"
|
|
outputs:
|
|
Delta: "Discriminant [V^2]"
|
|
I: "Current [A]"
|
|
logic:
|
|
- "Delta = (V_oc - v_p)^2 - 4 * R0 * P_tot"
|
|
- "I = (Delta >= 0) ? (V_oc - v_p - sqrt(Delta)) / (2 * R0) : NaN"
|
|
|
|
rhs:
|
|
description: "Computes the derivative vector and algebraic variables."
|
|
inputs:
|
|
t: "Time [s]"
|
|
x: "[z, v_p, T_b, S, w]"
|
|
u: "[L, C, N, Ψ, T_a]"
|
|
params: "MODEL_SPEC.parameters"
|
|
outputs:
|
|
dx_dt: "[dz/dt, dv_p/dt, dT_b/dt, dS/dt, dw/dt]"
|
|
algebraics: "{Delta, I, V_term, V_oc, R0, Q_eff, P_tot}"
|
|
logic:
|
|
- "V_oc, R0, Q_eff = params_to_constitutive(x, params)"
|
|
- "P_tot = power_mapping(u, x, params)"
|
|
- "Delta, I = current_cpl(V_oc, v_p, R0, P_tot)"
|
|
- "V_term = V_oc - v_p - I * R0"
|
|
- "dz_dt = -I / (3600 * Q_eff)"
|
|
- "dvp_dt = I/params.C1 - v_p / (params.R1 * params.C1)"
|
|
- "dTb_dt = (I^2 * R0 + I * v_p - params.hA * (T_b - T_a)) / params.C_th"
|
|
- "dS_dt = 0 (Single discharge assumption, or use MODEL_SPEC Option A)"
|
|
- "sigma_N = min(1, N)"
|
|
- "tau_N = (sigma_N >= w) ? params.tau_up : params.tau_down"
|
|
- "dw_dt = (sigma_N - w) / tau_N"
|
|
- "return [dz_dt, dvp_dt, dTb_dt, dS_dt, dw_dt], {Delta, I, V_term, V_oc, R0, Q_eff, P_tot}"
|
|
|
|
rk4_step:
|
|
logic:
|
|
- "u_n = scenario.u(t_n)"
|
|
- "k1, alg_n = rhs(t_n, x_n, u_n, params)"
|
|
- "k2, _ = rhs(t_n + dt/2, x_n + dt*k1/2, scenario.u(t_n + dt/2), params)"
|
|
- "k3, _ = rhs(t_n + dt/2, x_n + dt*k2/2, scenario.u(t_n + dt/2), params)"
|
|
- "k4, _ = rhs(t_n + dt, x_n + dt*k3, scenario.u(t_n + dt), params)"
|
|
- "x_next_raw = x_n + dt*(k1 + 2*k2 + 2*k3 + k4)/6"
|
|
- "x_next = [clamp(x_next_raw[0],0,1), x_next_raw[1], x_next_raw[2], clamp(x_next_raw[3],0,1), clamp(x_next_raw[4],0,1)]"
|
|
- "Store alg_n and x_n at t_n"
|
|
|
|
OutputSchema:
|
|
trajectory_columns:
|
|
- t
|
|
- z
|
|
- v_p
|
|
- T_b
|
|
- S
|
|
- w
|
|
- V_oc
|
|
- R0
|
|
- Q_eff
|
|
- P_tot
|
|
- Delta
|
|
- I
|
|
- V_term
|
|
metadata:
|
|
- dt
|
|
- t_max
|
|
- termination_reason
|
|
- t_star
|
|
- TTE_seconds
|
|
|
|
ValidationPlan:
|
|
convergence:
|
|
method: "step-halving"
|
|
metrics:
|
|
- "max_abs_diff_z: max|z_dt - z_dt2| < 1e-4"
|
|
- "rel_err_tte: |TTE_dt - TTE_dt2| / TTE_dt2 < 0.01"
|
|
feasibility:
|
|
guard: "If Delta < 0 at any rhs evaluation within RK4 stages, immediately trigger DELTA_ZERO event at current t_n."
|
|
action: "Record termination_reason = 'DELTA_ZERO' and invoke TTE_SPEC interpolation." |