cellpycore 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
cellpycore/__init__.py ADDED
File without changes
cellpycore/_helpers.py ADDED
@@ -0,0 +1,199 @@
1
+ """Helper functions only intended for development purposes (e.g. for creating mock data)."""
2
+
3
+ from typing import TypeVar
4
+
5
+ DataFrame = TypeVar("DataFrame")
6
+
7
+
8
+ def create_raw_data() -> DataFrame:
9
+ """Create mock raw battery testing data with realistic values.
10
+
11
+ TODO: This function was generated using AI and has not been checked for correctness!
12
+
13
+ Note that this function is called separately for each test that uses the mock_data_with_raw fixture.
14
+ If the test-suite is getting slow, consider caching the result of this function or using a different approach.
15
+ """
16
+ import polars as pl
17
+ from cellpycore.config import RawCols
18
+ from cellpycore.timestamps import NS_PER_SECOND
19
+
20
+ # Create a RawCols instance to get column names
21
+ raw_cols = RawCols()
22
+
23
+ # Generate realistic battery testing data
24
+ n_points = 1000 # Number of data points
25
+
26
+ # Create time series data
27
+ test_time = pl.Series(raw_cols.test_time, range(n_points), dtype=pl.Float64)
28
+ # epoch_time_utc is int64 nanoseconds since the Unix epoch, UTC (canonical
29
+ # absolute-timestamp dtype; see cellpycore.timestamps). Start at 2021-01-01 and
30
+ # advance one second per row.
31
+ start_epoch_s = 1609459200
32
+ epoch_time_utc = pl.Series(
33
+ raw_cols.epoch_time_utc,
34
+ [(start_epoch_s + i) * NS_PER_SECOND for i in range(n_points)],
35
+ dtype=pl.Int64,
36
+ )
37
+
38
+ # Generate cycle and step data
39
+ cycle_num = pl.Series(
40
+ raw_cols.cycle_num, [i // 100 for i in range(n_points)], dtype=pl.Int64
41
+ )
42
+ step_num = pl.Series(
43
+ raw_cols.step_num, [(i % 100) // 10 for i in range(n_points)], dtype=pl.Int64
44
+ )
45
+ datapoint_num = pl.Series(raw_cols.datapoint_num, range(n_points), dtype=pl.Int64)
46
+ source_datapoint_num = pl.Series(
47
+ raw_cols.source_datapoint_num, range(n_points), dtype=pl.Int64
48
+ )
49
+
50
+ # Generate step types (charge, discharge, rest)
51
+ step_types = []
52
+ for i in range(n_points):
53
+ step_idx = i % 10
54
+ if step_idx < 3:
55
+ step_types.append("charge")
56
+ elif step_idx < 6:
57
+ step_types.append("discharge")
58
+ else:
59
+ step_types.append("rest")
60
+
61
+ step_type = pl.Series(raw_cols.step_type, step_types, dtype=pl.Utf8)
62
+ step_type_detail = pl.Series(
63
+ raw_cols.step_type_detail, [f"{t}_cc" for t in step_types], dtype=pl.Utf8
64
+ )
65
+
66
+ # Generate current data (charge: positive, discharge: negative, rest: 0)
67
+ current = []
68
+ for i, st in enumerate(step_types):
69
+ if st == "charge":
70
+ current.append(1.0 + (i % 5) * 0.1) # 1.0 to 1.4 A
71
+ elif st == "discharge":
72
+ current.append(-1.0 - (i % 5) * 0.1) # -1.0 to -1.4 A
73
+ else:
74
+ current.append(0.0)
75
+
76
+ current = pl.Series(raw_cols.current, current, dtype=pl.Float64)
77
+
78
+ # Generate potential data (voltage)
79
+ potential = []
80
+ base_voltage = 3.7 # Typical Li-ion voltage
81
+ for i, st in enumerate(step_types):
82
+ if st == "charge":
83
+ # Voltage increases during charge
84
+ potential.append(base_voltage + (i % 100) * 0.01)
85
+ elif st == "discharge":
86
+ # Voltage decreases during discharge
87
+ potential.append(base_voltage - (i % 100) * 0.01)
88
+ else:
89
+ # Rest voltage
90
+ potential.append(base_voltage + (i % 10) * 0.001)
91
+
92
+ potential = pl.Series(raw_cols.potential, potential, dtype=pl.Float64)
93
+
94
+ # Generate cumulative capacities (cumulative per cycle, per direction).
95
+ cumulative_charge_capacity = []
96
+ cumulative_discharge_capacity = []
97
+ charge_cap = 0.0
98
+ discharge_cap = 0.0
99
+
100
+ for i, (curr, st) in enumerate(zip(current, step_types)):
101
+ if st == "charge":
102
+ charge_cap += abs(curr) * 0.1 # Assuming 0.1 hour time step
103
+ elif st == "discharge":
104
+ discharge_cap += abs(curr) * 0.1
105
+ cumulative_charge_capacity.append(charge_cap)
106
+ cumulative_discharge_capacity.append(discharge_cap)
107
+
108
+ cumulative_charge_capacity = pl.Series(
109
+ raw_cols.cumulative_charge_capacity,
110
+ cumulative_charge_capacity,
111
+ dtype=pl.Float64,
112
+ )
113
+ cumulative_discharge_capacity = pl.Series(
114
+ raw_cols.cumulative_discharge_capacity,
115
+ cumulative_discharge_capacity,
116
+ dtype=pl.Float64,
117
+ )
118
+
119
+ # Step time (seconds since the start of the current step) and instrument IR.
120
+ step_time = pl.Series(
121
+ raw_cols.step_time, [float(i % 10) for i in range(n_points)], dtype=pl.Float64
122
+ )
123
+ internal_resistance = pl.Series(
124
+ raw_cols.internal_resistance, [0.05] * n_points, dtype=pl.Float64
125
+ )
126
+
127
+ # Reference-electrode potential (3-electrode setup): the cell potential
128
+ # shifted by a small constant offset vs the reference electrode.
129
+ ref_potential = pl.Series(
130
+ raw_cols.ref_potential, [v - 0.2 for v in potential], dtype=pl.Float64
131
+ )
132
+
133
+ # Generate auxiliary temperature data
134
+ temperature_cell = pl.Series(
135
+ raw_cols.aux_temperature_cell,
136
+ [25.0 + (i % 20) * 0.5 for i in range(n_points)],
137
+ dtype=pl.Float64,
138
+ )
139
+ temperature_chamber = pl.Series(
140
+ raw_cols.aux_temperature_chamber,
141
+ [25.0 + (i % 10) * 0.2 for i in range(n_points)],
142
+ dtype=pl.Float64,
143
+ )
144
+
145
+ # Generate other metadata
146
+ source_type = pl.Series(raw_cols.source_type, ["maccor"] * n_points, dtype=pl.Utf8)
147
+ source_uuid = pl.Series(
148
+ raw_cols.source_uuid, [f"test_{i:06d}" for i in range(n_points)], dtype=pl.Utf8
149
+ )
150
+ step_mode = pl.Series(raw_cols.step_mode, ["CC"] * n_points, dtype=pl.Utf8)
151
+ pressure = pl.Series(
152
+ raw_cols.aux_pressure_cell,
153
+ [101325.0 + (i % 100) * 10 for i in range(n_points)],
154
+ dtype=pl.Float64,
155
+ )
156
+
157
+ # Create the DataFrame using the column names from RawCols
158
+ data = {
159
+ raw_cols.source_type: source_type,
160
+ raw_cols.source_uuid: source_uuid,
161
+ raw_cols.source_datapoint_num: source_datapoint_num,
162
+ raw_cols.datapoint_num: datapoint_num,
163
+ raw_cols.step_num: step_num,
164
+ raw_cols.cycle_num: cycle_num,
165
+ raw_cols.epoch_time_utc: epoch_time_utc,
166
+ raw_cols.test_time: test_time,
167
+ raw_cols.step_time: step_time,
168
+ raw_cols.step_mode: step_mode,
169
+ raw_cols.step_type: step_type,
170
+ raw_cols.step_type_detail: step_type_detail,
171
+ raw_cols.potential: potential,
172
+ raw_cols.current: current,
173
+ raw_cols.internal_resistance: internal_resistance,
174
+ raw_cols.ref_potential: ref_potential,
175
+ raw_cols.aux_temperature_cell: temperature_cell,
176
+ raw_cols.aux_temperature_chamber: temperature_chamber,
177
+ raw_cols.aux_pressure_cell: pressure,
178
+ raw_cols.cumulative_charge_capacity: cumulative_charge_capacity,
179
+ raw_cols.cumulative_discharge_capacity: cumulative_discharge_capacity,
180
+ }
181
+
182
+ return pl.DataFrame(data)
183
+
184
+
185
+ if __name__ == "__main__":
186
+ import matplotlib.pyplot as plt
187
+ df = create_raw_data()
188
+ df_pandas = df.to_pandas()
189
+
190
+ fig, axs = plt.subplots(2, 2, figsize=(10, 10))
191
+ axs[0, 0].plot(df_pandas["test_time"], df_pandas["potential"])
192
+ axs[0, 0].set_title("Potential")
193
+ axs[0, 1].plot(df_pandas["test_time"], df_pandas["current"])
194
+ axs[0, 1].set_title("Current")
195
+ axs[1, 0].plot(df_pandas["test_time"], df_pandas["aux_temperature_cell"])
196
+ axs[1, 0].set_title("Temperature Cell")
197
+ axs[1, 1].plot(df_pandas["test_time"], df_pandas["aux_temperature_chamber"])
198
+ axs[1, 1].set_title("Temperature Chamber")
199
+ plt.show()