Modeling the operation of a cell from real world energy storage system data #4147
-
BackgroundHi there, Im a stationary energy storage researcher in the electric utility space and I am very interested in PyBaMM, though much of the electrochemistry and physics in these models goes a bit over my head. I have 6 years of data from a large storage system (think large shipping containers filled with racks, filled with modules, filled with cells) where we have developed our own characterization of the degradation of this system over the years by analyzing periodic reference performance test data. I would like to use some or all of this data (mainly historical current and temperature timeseries) as the input to a PyBaMM model to see how these models show degradation under the same cycling and ambient conditions as the real system. So far I have had luck getting everything installed and am working with just a 1 hour snippet of my real system current data. Im trying to input this to a simple NMC model and, if everything worked out, I am hoping that PyBaMM would roughly model the same operation that I see in the real data for this 1-hour time period. Unfortunately, the simulation only makes it about 30 minutes into the cycling before stopping, it does not error out, but the simulation data just ends at around 1700 seconds. Some details about the real system I am trying to model
My Scriptimport pybamm
import matplotlib as mpl
import pandas as pd # needed to read the csv data file
import plotly.graph_objs as go
from plotly.offline import plot
from plotly.subplots import make_subplots
mpl.use('TkAgg') # or can use 'TkAgg', whatever you have/prefer
# import drive cycle data from file
all_data = pd.read_pickle("../Create Sample Data/Data/2017-2018_Rack1_Data.pickle")
# extract smaller portion of data
start = pd.to_datetime("2017-09-22 00:00:00")
end = pd.to_datetime("2017-09-22 01:00:00")
smaller_data = all_data.loc[start:end][[
'Container 1, Rack 1_StateOfCharge',
'Container 1, Rack 1_DC.Voltage_Avg of Cells',
'Container 1, Rack 1_Temp.Battery.Module_Avg of Modules',
'Container 1, Rack 1_DC.Current'
]]
# The rack from which this data originates is made of 17 modules (in series), where each module contains 28 cells in a
# 14S2P configuration. So, to get the cell-level current we divide the rack-level current by 2
smaller_data["Cell Current"] = smaller_data['Container 1, Rack 1_DC.Current'] / -2 # the sign convention might be backwards, so flip it
# create a seconds column
smaller_data["Seconds"] = (smaller_data.index - start).total_seconds()
drive_cycle = smaller_data[["Seconds", "Cell Current"]].to_numpy()
# Instantiate a simple model
model = pybamm.lithium_ion.DFN()
# load parameter values
param = model.default_parameter_values
# get predefined parameters for an NMC cell
param_mohtat = pybamm.ParameterValues("Mohtat2020")
# apply the SoC / Voltage relationship data from analyzing the real system data
param_mohtat["Open-circuit voltage at 0% SOC [V]"] = 3.2
param_mohtat["Open-circuit voltage at 100% SOC [V]"] = 4.17
param_mohtat["Upper voltage cut-off [V]"] = 4.2
# nominal capacity for JH3 cells (and a few other parameters) from LG Chem documentation
param_mohtat["Nominal cell capacity [A.h]"] = 63
param_mohtat["Cell volume [m3]"] = 5.65e-04
param_mohtat["Lower voltage cut-off [V]"] = 3
# create interpolant - must be a function of *dimensional* time
current_interpolant = pybamm.Interpolant(drive_cycle[:, 0], drive_cycle[:, 1], pybamm.t)
# set drive cycle
param_mohtat["Current function [A]"] = current_interpolant
output_variables = [
'Voltage [V]',
'Current [A]',
]
# set up simulation - for drive cycles we recommend using the CasadiSolver in "fast" mode
solver = pybamm.CasadiSolver(mode="fast")
simulation = pybamm.Simulation(model, parameter_values=param_mohtat)
# simulate US06 drive cycle (duration 600 seconds)
initial_soc = smaller_data['Container 1, Rack 1_StateOfCharge'].iloc[0] / 100
simulation.solve(initial_soc=initial_soc, showprogress=True)
solution = simulation.solution
# combine solution data for later plotting
solution_data = pd.concat([pd.Series(solution[var].entries, index=solution.t, name=var) for var in output_variables], axis=1)
# plot
# combine simulation data back into original EW Brown data
plot_data = pd.concat([smaller_data.reset_index().set_index("Seconds"), solution_data], axis=1)
plot_data = plot_data.loc[~plot_data["index"].isna()]
fig = make_subplots(rows=2, cols=1, shared_xaxes=True)
fig.add_trace(
go.Scattergl(
x=plot_data["index"],
y=plot_data['Current [A]'],
name='Cell Current (Rack Current / 2)',
mode="lines",
line=dict(width=1)
), row=1, col=1
)
fig.add_trace(
go.Scattergl(
x=plot_data["index"],
y=plot_data['Container 1, Rack 1_DC.Voltage_Avg of Cells'],
name='Rack Avg Cell Voltage',
mode="lines",
line=dict(width=1)
), row=2, col=1
)
fig.add_trace(
go.Scattergl(
x=plot_data["index"],
y=plot_data['Voltage [V]'],
name="Modeled Cell Voltage",
mode="lines",
line=dict(width=1)
), row=2, col=1
)
fig.update_layout(
yaxis=dict(title="Cell Current (A)"),
yaxis2=dict(title="Cell Voltage (V)"),
# yaxis3=dict(title="AmpHours")
)
plot(fig, filename="Plots/Real_vs_Modeled_Voltage.html") Simulation ResultsFinal Questions
Thanks in advance for any feedback! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 10 replies
-
Hi, it doesn't seem like you're doing anything wrong with the model but it's odd that if you give it a longer time series the sim stops with no error. I didn't have your file but this looks almost right for the current and scripts runs ok
|
Beta Was this translation helpful? Give feedback.
Although changing the nominal cell capacity will have little effect. You need to adjust electrode dimensions to change actual capacity. That's probably why your voltages are changing more than you expect