Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ionworks.com/llms.txt

Use this file to discover all available pages before exploring further.

Have you ever started a multi-day battery test, only to realize later that the protocol you used was incorrect? The Battery Cycler Simulator helps you prevent this by allowing you to upload a protocol file and run a quick physics-based simulation to verify its behavior before you start a real-world experiment.

How It Works

The process is simple: upload your protocol, configure your cell, and run the simulation.
  1. Upload: Upload your protocol file in the raw format (e.g. XML or JSON). The system automatically detects the format and parses it.
  2. Configure: Set the parameters for the cell you want to simulate.
  3. Simulate: Run the simulation and analyze the results.

Step 1: Upload Your Protocol File

You can start by uploading a protocol file from your computer. We currently support files from:
  • Arbin
  • BioLogic (.mps, .bttest)
  • Maccor (.xml, .csv)
  • Neware
  • Novonix (.pro2)
  • PyBaMM experiment strings (.txt)
Once you upload a file, the system immediately parses it and displays the translated steps.
Gamry .dta files are not protocol files and cannot be uploaded here. To import EIS measurement data from Gamry instruments, use the ionworksdata library — see Data format for details.

Required Additional Files

Some protocols reference external files for complex steps, such as custom drive cycle waveforms or reusable subroutines. If your protocol requires such files, the simulator will detect this and prompt you to upload them.

Step 2: Review and Configure

After parsing, you can review the protocol and set up the simulation.

Protocol Steps

The simulator displays the parsed protocol in three different formats, accessible via tabs:
  • Human-Readable: A simplified, easy-to-read summary of the steps in your protocol.
  • UCP (YAML): The full protocol translated into our Universal Cycler Protocol format. This shows the detailed underlying structure that will be executed.
  • Raw: The raw text content of the file you uploaded.

Cell Configuration

To run a meaningful simulation, you need to provide some basic information about the battery cell you want to test. This configures the underlying Equivalent Circuit Model (ECM) with one RC pair, using OCV and resistance parameters matched to your cell.
  • Chemistry: Select the cell chemistry from a list of pre-configured options (e.g., NMC/Graphite, LFP/Graphite). This determines the OCV curve and resistance values used by the model.
  • Cell capacity (Ah): The nominal capacity of your cell. The ECM parameters are scaled to match this capacity.
  • Resistance scale (%): Adjusts the model’s internal resistance relative to the default value for the selected chemistry. The default is 100% (no change). For example, set this to 200 to double the resistance or 50 to halve it. Useful for approximating cells with higher or lower impedance than the chemistry default.
  • Initial SOC (%): The State of Charge of the cell at the beginning of the simulation.
  • Temperature (°C): The ambient temperature for the simulation.
Check carefully that the cell configuration matches the cell for which the protocol was designed. If the cell configuration is incorrect, the simulation may not be able to run.

Advanced configuration

Under the Advanced section, you can configure optional rules that modify simulation behavior at runtime.

Termination conditions

Termination conditions let you stop a simulation early when a variable reaches a target value. This is useful for long cycling protocols where you only need to simulate a limited number of cycles or a specific amount of time. Each condition specifies a variable, a comparison operator (==, !=, >, <, >=, <=), and a value. The simulation stops as soon as any condition is met. The variable dropdown is organized into two groups:
  • Built-in — variables automatically provided by the simulation engine regardless of the protocol
  • Protocol variables — variables defined in and extracted from the parsed protocol
Total time
Total time is a built-in variable that tracks the cumulative elapsed simulation time in seconds. Use it to cap how long a simulation runs, independent of the protocol’s own step logic. When you select Total time, a unit picker appears next to the value field so you can enter the threshold in seconds, minutes, hours, or days. The value is automatically converted to seconds for the simulation engine. For example, to stop a long cycling protocol after 2 hours, add a termination condition where Total time >= 2 hours.
If the protocol defines its own variable named total_time, the protocol’s variable takes precedence and the built-in value is not injected.
Protocol variables
Protocol variables are extracted from your uploaded protocol file. For example, to stop an Arbin protocol after 3 cycles, you can add a condition where PV_CHAN_Cycle_Index >= 4. Arbin increments PV_CHAN_Cycle_Index at the start of each cycle, so the index reaches 4 only when the 4th cycle begins — meaning 3 full cycles have already completed. When a termination condition triggers, the reason is displayed in the simulation metrics using the human-readable form (e.g., “Early termination reason: Total time >= 2 hours”).

Variable callback rules

Variable callback rules let you dynamically update protocol variables during the simulation based on conditions. Each rule specifies a condition (variable, operator, value) and a set of variable updates to apply when the condition is met. For example, you could create a rule that increases the C-rate after a certain number of cycles: when PV_CHAN_Cycle_Index >= 3, update Current(A) to a higher value. This lets you simulate multi-phase protocols where charging or discharging parameters change at specific points during cycling.

Step 3: Run Simulation & Analyze Results

Once everything is configured, click Run Simulation. The simulator will execute the protocol against the configured cell model. You can cancel a running simulation at any time by clicking the Cancel button on the simulation page. This is useful for long-running protocols where you can already see the results you need.

Simulation results

Plots

The primary output is an interactive plot of your simulation data over time. By default, Voltage and Current are shown, but you can configure exactly which variables appear. Click Configure Plot to open the plot settings drawer. Under Time Series, toggle any of the available variables on or off:
VariableUnitDescription
VoltageVCell terminal voltage
CurrentAApplied current
Temperature°CCell temperature (when available)
Charge capacityAhCumulative charge capacity
Discharge capacityAhCumulative discharge capacity
State of charge%Cell state of charge (when available)
Step countOverall step index
Cycle countCurrent cycle number
Step count (within cycle)Step number within the current cycle
Each enabled variable is displayed in its own subplot, stacked vertically and sharing a common time axis. Charge capacity and discharge capacity are grouped into a single subplot for easy comparison.
If your protocol defines numeric variables (e.g., C-rate, temperature setpoints), you can also plot these as time series. In the Configure Plot drawer, use the Additional Variables dropdown to select any numeric protocol variable. The selected variables appear as additional subplots alongside the built-in time series.

Key metrics

Below the plot, you will find key performance indicators calculated from the simulation, including:
  • Total Time
  • Charge Throughput (Ah)
  • Energy Throughput (Wh)
  • Early termination reason (if a termination condition was triggered)

Fullscreen mode

Click the fullscreen icon in the top-right corner of the plot to expand it to fill the screen. The fullscreen view includes the same Configure Plot button, so you can adjust which variables are shown without leaving fullscreen. By simulating your protocols, you can catch errors, validate your experimental design, and gain confidence before committing time and resources to a real test.

Differences between Commercial Protocols

Much of the challenge in converting between the different protocols is not the syntax, but the fundamental differences in how the cyclers define the logic to follow the same sequence of steps. In this section, we’ll cover some implementation differences between the Ionworks Universal Cycler Protocol, and the protocols from the cyclers we support.

CCCV steps

Most cyclers define CCCV steps as one step with voltage as a “limit” field:
  • Maccor: Uses a constant current step, with voltage as a “limit”. Maccor also supports a native single-step Chg Func CCCV / Dis Func CCCV step type that combines the CC and CV phases (with the CV cutoff specified as a current limit).
  • Neware: Specifies both current and voltage as a “limit”
  • Novonix: Specifies both current and voltage as fields, and uses step type to differentiate between CC (voltage is a cutoff) and CCCV (transition to voltage and hold until a current cutoff)
In UCP, for maximum modularity, we use a step block with two steps, CC with a voltage cut-off and CV with a current cut-off, with total duration and any other end conditions defined at the step block level. When parsing a Maccor Chg Func CCCV / Dis Func CCCV step, the parser expands it into the equivalent two-step UCP block automatically.

Header metadata

Some formats (e.g., Novonix .pro2) include top-level header data (Version, LastUpdated, Charger). This metadata is preserved in UCP under header and is used for round-trips when converting back to the original format.

Functional expressions

Maccor supports functional expressions (e.g., VAR1*0.5) for step values and end conditions. These are carried through UCP as strings and round-tripped using vendor-specific constructs (e.g., Maccor “User Def” end entries), so the meaning is preserved even if another format lacks an exact equivalent.

Nested loops

For formats that use Do/Loop constructs (Maccor), nested loops are numbered (Do 1/Loop 1, Do 2/Loop 2, …) to reflect structure. UCP expresses loops with repeat on a block; when converting back to Maccor, Do/Loop numbering is generated from the block nesting depth.

Report/Record/Save data/Resolution

This is the field that defines how often the cycler will save data to the output time series.
  • Maccor uses the “Report” field and allows time, current, voltage, and temperature
  • Neware uses the “Record” field and allows time, current, and voltage
  • Novonix uses StepConditions entries with ConditionType: "Save data" and allows Δt, ΔV, and ΔI.
  • UCP uses the “Resolution” field, which can be set globally and overridden for each step, and currently only supports time

Loops

For loops, there are two fundamental approaches:
  1. Nested Steps: Define the loop as a step block with a nested step, with a repeat parameter specifying the number of times to repeat the loop. This is the more modern approach, similar to how loops are defined in modern programming languages such as Python.
The following protocols use this approach:
  • UCP (using step blocks)
  • Novonix (using ChildProtocolStepList with TimesToLoop).

Increment cycle number

  • Novonix uses StepType = 6 to increment the cycle counter. In UCP this maps to an auxiliary Increment cycle number step.
  • Arbin uses the built-in PV_CHAN_Cycle_Index variable to track the current cycle. When this variable is incremented via a Set Variable(s) step, it maps to both a set_variable action and an Increment cycle number auxiliary step in UCP.
  1. Goto/State machine: Define special steps like “start loop” and “end loop”. This is the more legacy approach, similar to older programming languages such as Fortran.
The following protocols use this approach:
  • Maccor (using a Do step to start the loop, and a Loop step to end the loop)
  • Neware (using a special step type to loop back to a specified previous step a certain number of times)
  • Arbin (using limit conditions with goto targets to jump between steps, and Set Variable(s) steps to manage counters)

Cycle-index branching (Arbin)

Arbin protocols commonly use PV_CHAN_Cycle_Index to implement cycle-dependent branching, where different parameters are applied on different cycles. When parsed into UCP, this pattern is represented using control steps with set_variable actions and goto targets.

PyBaMM experiment strings

You can upload a plain text file containing PyBaMM experiment strings directly into the Battery Cycler Simulator. The system auto-detects the format and converts the steps into UCP, with list repetition blocks mapping to step blocks with a repeat count.

Basic syntax

For plain steps, each line in the file is a single PyBaMM step string. The supported step types are:
  • Charge at <value> <unit> — constant current, C-rate, or power charge
  • Discharge at <value> <unit> — constant current, C-rate, or power discharge
  • Hold at <value> V — constant voltage hold
  • Rest for <duration> — open-circuit rest period
Steps can include termination conditions with until and duration constraints with for:
Charge at 1C until 4.2V
Discharge at 0.5C for 1 hour
Hold at 4.2V until C/50
Rest for 10 minutes

List repetition

To repeat a sequence of steps multiple times, wrap them in square brackets and multiply with * N. This is equivalent to Python’s list repetition syntax.
["Charge at 1C until 4.2V", "Discharge at 1C until 2.5V"] * 100
This produces a single repeated block in UCP with repeat: 100, rather than duplicating the steps 100 times. You can mix repeated blocks with plain steps:
Charge at 1C until 4.2V
Hold at 4.2V until C/50
["Discharge at 0.5C until 3.0V", "Rest for 10 minutes"] * 50
Rest for 1 hour

Nested repetition

Repeated blocks can be nested for more complex protocols:
[["Charge at 1C until 4.2V", "Rest for 5 minutes"] * 2, "Discharge at 1C until 2.5V"] * 30
This creates an outer block that repeats 30 times, where each iteration runs the charge-rest pair twice followed by a single discharge.

Cycle groups

Use parentheses inside a list to mark a group of steps as a cycle. This automatically inserts an “Increment cycle number” step at the end of each repetition, so cycle-level metrics are tracked correctly:
[("Charge at 1C until 4.2V", "Discharge at 1C until 2.5V")] * 100
Tuple cycle groups must always be inside a list. Use [(...)] * N — not (...) * N.

Multiline format

For readability, you can split a repeated block across multiple lines:
[
    "Charge at 1C until 4.2V",
    "Hold at 4.2V until C/50",
    "Discharge at 1C until 2.5V",
] * 50