Skip to content

Quickstart on mock data

This notebook runs the whole cellpy-core pipeline — Data.from_raw_framemake_step_tablemake_summary — on synthetic data, so it works anywhere the cellpycore package is installed (no cycler files needed).

The mock frame comes from cellpycore.testing.mock_data.create_raw_data, which produces 1000 rows of charge / discharge / rest steps in the harmonized raw schema.

import matplotlib.pyplot as plt

import cellpycore
from cellpycore import Data, make_step_table, make_summary
from cellpycore.testing.mock_data import create_raw_data

print(f"cellpycore version: {cellpycore.__version__}")
cellpycore version: 0.1.3

1. Create a raw frame

A raw frame is an ordinary polars DataFrame whose columns follow the harmonized raw schema (cellpycore.config.RawCols).

raw = create_raw_data()
raw.select(
    "test_time", "cycle_num", "step_num", "step_type", "current", "potential"
).head()
shape: (5, 6)
test_timecycle_numstep_numstep_typecurrentpotential
f64i64i64strf64f64
0.000"charge"1.03.7
1.000"charge"1.13.71
2.000"charge"1.23.72
3.000"discharge"-1.33.67
4.000"discharge"-1.43.66
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 5), sharex=True)
ax1.plot(raw["test_time"], raw["potential"], lw=0.8)
ax1.set_ylabel("potential (V)")
ax2.plot(raw["test_time"], raw["current"], lw=0.8, color="tab:orange")
ax2.set_ylabel("current (A)")
ax2.set_xlabel("test_time (s)")
fig.suptitle("Mock raw data")
fig.tight_layout()

png

2. Run the pipeline

Data.from_raw_frame is the validating front door: it checks that the frame carries the load-bearing columns with sane dtypes and reports every problem in a single error. Then the step table must be built before the summary, because make_summary reads data.steps.

data = Data.from_raw_frame(raw)
make_step_table(data, nom_cap=1.0)  # nom_cap (absolute, Ah) sets the per-step C-rate
make_summary(data)

print(f"steps:   {data.steps.height} rows")
print(f"summary: {data.summary.height} cycles")
steps:   100 rows
summary: 10 cycles

3. Inspect the step table

One row per sequential step, with per-step statistics (first / last / min / max / mean of current, potential, capacities …) and the classified step_type.

data.steps.select(
    "cycle_num",
    "step_num",
    "step_type",
    "current_mean",
    "potential_first",
    "potential_last",
    "charge_capacity_last",
    "discharge_capacity_last",
).head(8)
shape: (8, 8)
cycle_numstep_numstep_typecurrent_meanpotential_firstpotential_lastcharge_capacity_lastdischarge_capacity_last
i64i64strf64f64f64f64f64
00"cv_discharge"-0.043.73.7090.330.37
01"discharge"-0.043.83.7090.660.74
02"discharge"-0.043.93.7090.991.11
03"discharge"-0.044.03.7091.321.48
04"discharge"-0.044.13.7091.651.85
05"discharge"-0.044.23.7091.982.22
06"discharge"-0.044.33.7092.312.59
07"discharge"-0.044.43.7092.642.96

4. Inspect the per-cycle summary

One row per cycle: capacities, coulombic efficiency, durations, and per-direction current / potential statistics.

data.summary.select(
    "cycle_num",
    "charge_capacity",
    "discharge_capacity",
    "coulombic_efficiency",
    "last_test_time",
)
shape: (10, 5)
cycle_numcharge_capacitydischarge_capacitycoulombic_efficiencylast_test_time
i64f64f64f64f64
03.33.7112.12121299.0
16.67.4112.121212199.0
29.911.1112.121212299.0
313.214.8112.121212399.0
416.518.5112.121212499.0
519.822.2112.121212599.0
623.125.9112.121212699.0
726.429.6112.121212799.0
829.733.3112.121212899.0
933.037.0112.121212999.0
summary = data.summary
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(summary["cycle_num"], summary["charge_capacity"], "o-", label="charge")
ax.plot(summary["cycle_num"], summary["discharge_capacity"], "s-", label="discharge")
ax.set_xlabel("cycle number")
ax.set_ylabel("capacity (Ah)")
ax.set_title("Per-cycle capacities (mock data)")
ax.legend()
fig.tight_layout()

png

Next steps