Code:
import pybamm
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error
Set logging level
pybamm.set_logging_level(“WARNING”)
Create model
model = pybamm.lithium_ion.DFN(
options={
“cell geometry”: “pouch”,
}
)
Create parameter set
parameter_values = pybamm.ParameterValues(“OKane2022”)
Calculate total width
parameter_values.update({
# Cell geometry
"Nominal cell capacity [A.h]": 65,
"Electrode width [m]": 1.58 * 62/5,
"Current function [A]": 65.0,
})
Import drive cycle
drive_cycle = pd.read_csv(
r"C:\Users\OO000009\Desktop------.csv",
comment=“#”,
header=None
).to_numpy()
drive_cycle[:, 1] = -drive_cycle[:, 1]
Load experimental data
experimental_data = pd.read_csv(r"C:\Users\OO000009\Desktop-----.csv")
exp_time_s = experimental_data[“Total Time (Seconds)”]
exp_voltage_mV = experimental_data[“Voltage (mV)”]
Convert voltage from mV to V
exp_voltage_V = exp_voltage_mV / 1000
Skip the first 3200 rows and reset time to start from 0
exp_time_s = exp_time_s.iloc[3200:].reset_index(drop=True)
exp_voltage_V = exp_voltage_V.iloc[3200:].reset_index(drop=True)
exp_time_s = exp_time_s - exp_time_s.iloc[0] # Reset time to start from 0
Create drive cycle experiment
def create_experiment(num_cycles):
# Create drive cycle step using the current function
drive_cycle_step = pybamm.step.current(drive_cycle)
# Create cycling experiment
cycle_steps = [
(drive_cycle_step,) # Add rest between cycles
] * num_cycles
return pybamm.Experiment(cycle_steps)
Use drive cycle experiment
experiment = create_experiment(num_cycles=100)
Solver settings
solver = pybamm.CasadiSolver(
mode=“safe”,
atol=1e-6, # Stricter tolerance
rtol=1e-6,
dt_max=600, # Smaller timestep
)
Create and run simulation
sim = pybamm.Simulation(
model,
parameter_values=parameter_values,
experiment=experiment,
solver=solver
)
print(“Starting simulation…”)
solution = sim.solve(initial_soc=0.3)
Extract data for plotting
voltage = solution[“Terminal voltage [V]”].entries
time = solution[“Time [s]”].entries
Interpolate experimental data to match simulation time points
exp_voltage_interp = np.interp(time, exp_time_s, exp_voltage_V)
Calculate RMSE between simulated and experimental voltage
rmse = np.sqrt(mean_squared_error(exp_voltage_interp, voltage))
print(f"Root Mean Squared Error (RMSE) between simulated and experimental voltage: {rmse:.4f} V")
Plot voltage comparison
plt.figure(figsize=(12, 6))
plt.plot(time, voltage, label=“Simulated Voltage”, color=“royalblue”, linewidth=2.5)
plt.plot(time, exp_voltage_interp, label=“Experimental Voltage”, color=“darkorange”, linewidth=2.5)
plt.xlabel(“Time [s]”)
plt.ylabel(“Voltage [V]”)
plt.title(“Voltage Comparison”)
plt.legend()
plt.grid(True)
plt.show()
Track capacity over cycles
cycle_numbers =
capacities =
capacity_losses =
Check if capacity data exists in solution summary variables
if “Capacity [A.h]” in solution.summary_variables:
initial_capacity = solution.summary_variables[“Capacity [A.h]”][0]
capacities = solution.summary_variables[“Capacity [A.h]”]
capacity_losses = ((initial_capacity - np.array(capacities)) / initial_capacity) * 100
# Print capacity values for each cycle
print("Cycle-wise capacities and capacity losses:")
for cycle_number, (capacity, capacity_loss) in enumerate(zip(capacities, capacity_losses), start=1):
print(f"Cycle {cycle_number}: Capacity = {capacity:.2f} Ah, Capacity Loss = {capacity_loss:.2f} %")
# Plot results
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 10))
# Capacity plot
ax1.plot(range(1, len(capacities) + 1), capacities, 'b-o')
ax1.set_xlabel('Cycle Number')
ax1.set_ylabel('Capacity [Ah]')
ax1.grid(True)
ax1.set_title('Capacity vs Cycle Number')
# Capacity loss plot
ax2.plot(range(1, len(capacities) + 1), capacity_losses, 'r-o')
ax2.set_xlabel('Cycle Number')
ax2.set_ylabel('Capacity Loss [%]')
ax2.grid(True)
ax2.set_title('Capacity Loss vs Cycle Number')
plt.tight_layout()
plt.show()
else:
print(“Capacity data is not available in the solution’s summary variables.”)
# Calculate RMSE between simulated and experimental voltage
rmse = np.sqrt(mean_squared_error(exp_voltage_interp, voltage))
print(f"Root Mean Squared Error (RMSE) between simulated and experimental voltage: {rmse:.4f} V")