Dyad component reference

What each component in the library offers. For building and running a model, see Building a model.

The circuit equations are authored in dyad/ecm.dyad. EquivalentCircuitCell selects the topology through the structural ECMTopology enum:

ChoiceCircuit
ECMTopology.Rint()OCV and series resistance
ECMTopology.Thevenin()n_rc polarization branches
ECMTopology.DualPolarization()Two polarization branches
ECMTopology.PNGV()One polarization branch and local OCV-drift capacitor
ECMTopology.BulkSurface()Linear SAFT bulk/surface capacitor network
ECMTopology.ChenRinconMora()Published SOC-dependent two-RC fit

EDLC, the double-layer capacitor cell, has no ECMTopology variant. Exposing it here needs a native circuit component and a matching BatteryParameterSet entry for the device data; until then it is built from Julia, with BatteryCell(; model = EDLC(), chemistry = MaxwellPC2500()).

For example, this Dyad declaration selects a dual-polarization cell:

battery = BatteryComponents.EquivalentCircuitCell(
  topology=BatteryComponents.ECMTopology.DualPolarization(),
  capacity=100.0, SOC_initial=0.5,
  R0=0.02402, R_dp=[0.00064, 0.00824], C_dp=[5630.0, 54277.0])

Connect its p and n electrical pins and supply battery.ocv in volts from an OCV component. Generic Rint and Thevenin circuits deliberately accept an OCV signal so the user can choose the chemistry's OCV law. PNGV uses the fixed U0 parameter and a drift capacitor instead; the bulk/surface circuit uses U0 only for initialization. Chen–Rincón-Mora includes its published OCV law.

All parameters use SI units, except capacity in Ah and SOC as a fraction. Resistance and capacitance inputs to the reusable primitives may be functions of SOC supplied by other native components. Positive reported I means discharge; connector current follows the passive convention, so p.i = -I. A resistive load therefore receives positive power while SOC decreases.

Packs use the existing setup

BatteryCell, BatteryPack and CyclingCircuit retain their existing interface and now use the same Dyad-generated polarization, charge-storage and ohmic components. The adapter provides the parameter dictionaries, legacy variable names, stop bounds and thermal/pack integration. It does not maintain a second handwritten copy of the polarization or capacitor dynamics.

using BatteryComponents, ModelingToolkit

@named pack = BatteryPack(model=ECMTopology.DualPolarization(),
    chemistry=He2011LiMn2O4(), series=2, parallel=3)

@named circuit = CyclingCircuit(model=ECMTopology.DualPolarization(),
    chemistry=He2011LiMn2O4(), series=2, parallel=3,
    protocol=[discharge(0.3C), rest(time=9000)])

The existing Julia selectors (DP(), Thevenin(2), etc.) remain supported. A first-order Thevenin() defaults to the one-RC He parameter set; the two-RC model defaults to Chen–Rincón-Mora. Higher orders require an explicit parameter set, since no higher-order fit is supplied.

All battery models use the same electrical interface: current entering p charges the battery, and reported discharge-positive current is I = -p.i. A passive load therefore receives power while SOC falls. The same Cycler connects to ECM, SPM, SPMe and DFN cells without a model-specific setting.

The Julia parameter-dictionary API binds parameters and signals to the native RintCircuit, TheveninCircuit, PNGVCircuit or BulkSurfaceCircuit component. The convenience Dyad cells use these same circuits. Julia does not assemble a second topology or implement a separate set of circuit dynamics.

Health and degradation

ECMDegradation.NoDegradation() is the default: SOH and the resistance factor are one. The ECMs do not predict SEI growth or loss of active material. Those models in the electrochemical API depend on electrode states an ECM does not resolve.

ECMDegradation.PrescribedHealth() exposes capacity_health and resistance_growth inputs. The first is available capacity divided by nominal capacity; the second multiplies all circuit resistances. Capacitances and the OCV law are unchanged. These signals can come from a separately calibrated Dyad aging component or from measured health data. This option is not an aging prediction law and carries no chemistry-independent lifetime claim.

The normalized SOC equation is der(SOC) = -I / (3600 * capacity * SOH). This is an empirical coulomb-counting convention using instantaneous capacity, not a model of lithium inventory loss. Health must remain in (0, 1] and resistance scaling must remain positive. The native health component asserts these domains.

The same degradation enum is accepted by BatteryPack. For prescribed health, connect the pack's capacity_health and resistance_growth array inputs, each with shape (series, parallel). The pack reports mean SOH and aggregate available capacity. C-rate protocol setpoints continue to use the nominal capacity, as in the existing cycler.

Thermal interpretation

Q_loss reports resistor dissipation. It is a circuit accounting quantity, not an experimentally validated battery heat-generation model. In particular, a SOC-dependent fitted capacitance is not automatically a physical energy store with energy C*U^2/2. ECMThermalMass accepts a separately specified heat input and conserves heat through its two native thermal ports. The shared pack's temperature=true closure uses resistor dissipation and an optional entropic term; its physical adequacy must be checked for the chosen cell and operating conditions.

Validation and reproducibility

test/ecm_native.jl exercises the generated native components with electrical loads, current pulses, rest, charging, unrelaxed initial conditions, enum selection and prescribed health. References include exact exponential branch responses, the analytic bulk/surface solution, and charge/power balances. test/ecm.jl exercises the existing pack and cycler API, including series and parallel scaling for each circuit family.

test/reference/chen2006.jl independently integrates equations (1)–(7) of Chen and Rincón-Mora using an independent Julia RK4 implementation. Step halving from 0.5 s to 0.25 s changes the saved reference values by less than 1e-9. The checked-in reference covers 80 mA continuous discharge through 37000 s. These are numerical equation references, not measured data; the tests do not establish the paper's reported experimental voltage or runtime error.

He et al. supplies the circuit comparison and parameter tables. Table 5's printed capacitance and time constant disagree. The parameter set preserves the printed 54277 F; using 5427.7 F is an explicit alternative interpretation, not a confirmed correction. Parameter applicability and the local SOC window are documented under He2011LiMn2O4.

The generated files were produced with Dyad CLI 3.5.0, source revision a0c9fcaf7ff6deec23938247e05245883a2aabe1. Regenerate with dyad compile ., then format generated/ with JuliaFormatter 1.0.62, the same version used by this repository's format check. OrdinaryDiffEqDefault and RuntimeGeneratedFunctions are runtime dependencies because the compiler imports them in the generated component preamble. Markdown supplies the generated docstrings.

The shared BatteryPack builder represents a whole pack as a fixed set of array equations over the (series, parallel) axes, for both ECMs and electrochemical models, and a BatteryCell is the 1 × 1 pack. The equivalent circuits are written directly as those array equations. The electrochemical models are written as array equations over their spatial grids as well: every distributed quantity is one array with its grid axes ahead of the pack axes, so the number of equations depends on neither the pack dimensions nor the grid resolution. mtkcompile scalarizes the array equations again, so numerical storage and solve work still grow with the number of cells and grid points.

Native API

The generated API is included once in the API overview:

BatteryComponents.ECMDegradation — Module
ECMDegradation

Dyad structural health selection. NoDegradation() fixes health at one; PrescribedHealth() accepts available-capacity and resistance-scaling signals from an independently calibrated aging model. It does not predict aging itself.

source

The shared ArrayBatteryPack selects its constitutive model, parameter set, thermal treatment and electrochemical degradation with five more structural enums:

BatteryComponents.BatteryThermalModel — Module
BatteryThermalModel

Structural thermal selection for ArrayBatteryPack: Isothermal, Lumped, or Distributed. Distributed temperature requires an electrochemical model. Adjacent parallel cells share thermal boundary temperatures and exchange heat.

source
BatteryComponents.SEIParameterSet — Module
SEIParameterSet

Published SEI parameter set for ArrayBatteryPack: PETLION, Ramadass2004 or PyBaMM. It parameterises the SEI submodel that BatteryElectrodeSelection enables, so it has no effect with SEI growth disabled, and a non-default set is rejected for an equivalent circuit, which has no SEI submodel. The sets and what separates them are in BatteryComponents.SEI_degradation_default_params.

source