SLIDE  3.0.0
A simulator for lithium-ion battery pack degradation
Loading...
Searching...
No Matches
Cell_ECM.hpp
Go to the documentation of this file.
1/*
2 * Cell_ECM.hpp
3 *
4 * Created on: 17 Dec 2019
5 * Author(s): Jorn Reniers, Volkan Kumtepeli
6 */
7
8#pragma once
9
10#include "../Cell.hpp"
11#include "State_ECM.hpp"
12#include "../../utility/utility.hpp"
13#include "../../settings/settings.hpp"
14
15#include <cstring>
16#include <cassert>
17#include <iostream>
18#include <fstream>
19#include <string>
20#include <cstdlib>
21#include <cmath>
22#include <algorithm>
23#include <array>
24
25namespace slide {
26
27template <size_t N_RC = 1>
28class Cell_ECM : public Cell
29{
30
31protected:
34
35 std::array<double, N_RC> Rp{}, inv_tau{}; // inv_tau = 1/(RC). All initialised zero.
36 // double Rp{ 15.8e-3 }, Cp{ 38e3 }; //!< parallel resistance and capacitance
38 double Rdc{ 2e-3 };
39
40public:
41 Cell_ECM();
42 Cell_ECM(double capin, double SOCin);
43 Cell_ECM(double capin, double SOCin, double Rdc_, std::array<double, N_RC> Rp_, std::array<double, N_RC> inv_tau_);
44
45 Cell_ECM(std::string IDi, double capin, double SOCin, double Rdc_, std::array<double, N_RC> Rp_, std::array<double, N_RC> inv_tau_)
46 : Cell_ECM(capin, SOCin, Rdc_, Rp_, inv_tau_)
47 {
48 ID = std::move(IDi);
49 }
50
51
52 Cell_ECM(std::string IDi, double capin, double SOCin)
53 : Cell_ECM(capin, SOCin)
54 {
55 ID = std::move(IDi);
56 }
57
58 Cell_ECM(std::string IDi) : Cell_ECM() { ID = std::move(IDi); }
59
60 inline double I() const override { return st.I(); }
61 inline double getIr() { return st.Ir(); }
62 inline double SOC() override { return st.SOC(); }
63 inline double T() override { return st.T(); }
64
66 std::span<double> viewStates() override { return std::span<double>(st.begin(), st.end()); }
67 void getStates(getStates_t s) override { s.insert(s.end(), st.begin(), st.end()); }
68
69 auto &getStateObj() { return st; }
70
71 double V() override;
72 Status setStates(setStates_t s, bool checkStates = true, bool print = true) override;
73
74 double getRtot() override { return Rdc; }
75 double getThotSpot() override { return T(); }
76 double getThermalSurface() override { return 0; };
77 double getOCV() override { return OCV.interp(st.SOC(), settings::printBool::printCrit); } // Linear interpolation #TODO add a OCV model.
78
79 Status setSOC(double SOCnew, bool checkV = true, bool print = true) override;
80 Status setCurrent(double Inew, bool checkV = true, bool print = true) override;
81 Status setVoltage(double Vnew, bool checkI = true, bool print = true) override;
82
83 inline void setT(double Tnew) override { st.T() = Tnew; }
84
85 virtual bool validStates(bool print = true) override;
86 void timeStep_CC(double dt, int steps = 1) override;
87
88 ThroughputData getThroughputs() override { return { st.time(), st.Ah(), st.Wh() }; }
89
90 Cell_ECM<N_RC> *copy() override { return new Cell_ECM<N_RC>(*this); }
91};
92
93// Implementation:
94
98template <size_t N_RC>
100{
101 ID = "Cell_ECM<" + std::to_string(N_RC) + ">";
102 capNom = 16;
104 OCV.x = slide::linspace_fix(0.0, 1.0, 3);
105 OCV.y = slide::linspace_fix(VMIN(), VMAX(), 3);
106
107 if constexpr (N_RC >= 1) {
108 constexpr double Cp0 = 38e3; // first parallel capacitance
109 Rp[0] = 15.8e-3; // fist parallel (polarisation) resistance default value.
110 inv_tau[0] = 1.0 / (Rp[0] * Cp0);
111 }
112
113 if constexpr (N_RC == 2) {
114 Rp[1] = 2.5e-3; // second parallel (polarisation) resistance default value.
115 inv_tau[1] = 1.0 / 100.0;
116 }
117
118 OCV.check_is_fixed();
119 cellData.initialise(*this);
120}
121
127template <size_t N_RC>
128inline Cell_ECM<N_RC>::Cell_ECM(double capin, double SOCin) : Cell_ECM()
129{
131 if (!free::check_SOC(SOCin)) throw 10;
132
133 st.SOC() = SOCin;
134 setCapacity(capin);
135}
136
145template <size_t N_RC>
146inline Cell_ECM<N_RC>::Cell_ECM(double capin, double SOCin, double Rdc_,
147 std::array<double, N_RC> Rp_,
148 std::array<double, N_RC> inv_tau_)
149 : Cell_ECM(capin, SOCin)
150{
151 Rdc = Rdc_;
152 Rp = Rp_;
153 inv_tau = inv_tau_;
154}
155
156
181template <size_t N_RC>
182inline Status Cell_ECM<N_RC>::setCurrent(double Inew, bool checkV, bool print)
183{
184 const double Iold = I();
185 st.I() = Inew;
186
187 const auto status = checkCurrent(checkV, print);
188
189 if (isStatusBad(status))
190 st.I() = Iold;
191
192 return status;
193}
194
202template <size_t N_RC>
203inline Status Cell_ECM<N_RC>::setVoltage(double Vnew, bool checkI, bool print)
204{
205 const double Iold = st.I();
206 // #TODO check if V is sensible here.
207
208 const double ocv = getOCV();
209 double v_now = ocv - Vnew;
210
211 for (size_t i{}; i < N_RC; i++)
212 v_now -= Rp[i] * st.Ir(i);
213
214 const auto Inew = v_now / Rdc;
215
216 st.I() = Inew;
217
218 const auto status = checkCurrent(checkI, print);
219
220 if (isStatusBad(status))
221 st.I() = Iold;
222
223 return status;
224}
225
239template <size_t N_RC>
240inline Status Cell_ECM<N_RC>::setSOC(double SOCnew, bool checkV, bool print)
241{
242 if (!free::check_SOC(SOCnew))
244
245 const double SOCold = st.SOC();
246
247 st.SOC() = SOCnew;
248
249 if (checkV) {
250 double v;
251 const auto status = checkVoltage(v, print);
252
253 if (isStatusBad(status))
254 st.SOC() = SOCold;
255
256 return status;
257 }
258
259 return Status::Success;
260}
261
269template <size_t N_RC>
270inline double Cell_ECM<N_RC>::V()
271{
272 const bool verb = settings::printBool::printCrit;
273 try {
274 const double ocv = getOCV();
275 double v_now = ocv - Rdc * st.I();
276
277 for (size_t i{}; i < N_RC; i++)
278 v_now -= Rp[i] * st.Ir(i);
279
280 return v_now;
281 } catch (int e) {
282 if (verb)
283 std::cerr << "ERROR in Cell_ECM::getV when getting the OCV.\n";
284 return 0;
285 }
286}
287
288template <size_t N_RC>
289inline Status Cell_ECM<N_RC>::setStates(setStates_t s, bool checkV, bool print)
290{
291 /*
292 */
293 const auto st_old = st;
294
295 std::copy(s.begin(), s.begin() + st.size(), st.begin());
296 s = s.last(s.size() - st.size());
297
298 const Status status = free::check_Cell_states(*this, checkV);
299
300 if (isStatusBad(status))
301 st = st_old;
302
303 return status;
304}
305
306template <size_t N_RC>
307inline bool Cell_ECM<N_RC>::validStates(bool print)
308{
309 /*
310 * note: does NOT check the voltage, only whether all fields are in the allowed range
311 * throws
312 * 10 invalid array (wrong length)
313 */
314
315 const bool verb = print && (settings::printBool::printCrit);
316
318
319 bool range = free::check_SOC(SOC());
320
321 if (T() < Tmin() || T() > Tmax()) {
322 if (verb)
323 std::cerr << "ERROR in Cell_ECM::validState, T is outside of the range, "
324 << Tmin() << " <= T <= " << Tmax()
325 << ", value is " << T() << '\n';
326 range = false;
327 }
329
330 return range;
331}
332
333template <size_t N_RC>
334inline void Cell_ECM<N_RC>::timeStep_CC(double dt, int nstep)
335{
336 /*
337 * take a time step of dt seconds while keeping the current constant
338 */
339 if (dt < 0) {
340 if constexpr (settings::printBool::printCrit)
341 std::cerr << "ERROR in Cell_ECM::timeStep_CC, the time step dt must be "
342 << "0 or positive, but has value " << dt << '\n';
343 throw 10;
344 }
345
346 const auto dth = dt / 3600.0;
348 for (int t = 0; t < nstep; t++) {
350 const auto dAh = st.I() * dth;
351 st.SOC() -= dAh / Cap();
352
353 for (size_t i{}; i < N_RC; i++) // dIr/dt = (I - Ir)/(RC)
354 st.Ir(i) += dt * inv_tau[i] * (st.I() - st.Ir(i));
355
358 st.time() += dt;
359 st.Ah() += std::abs(dAh);
360 st.Wh() += std::abs(dAh * V());
361 }
362 }
363}
364
366
367} // namespace slide
State_ECM class definition.
Definition: Cell_ECM.hpp:29
ThroughputData getThroughputs() override
Definition: Cell_ECM.hpp:88
State_ECM< N_RC > st
parameters:
Definition: Cell_ECM.hpp:32
std::span< double > viewStates() override
Only for cells to see individual states.
Definition: Cell_ECM.hpp:66
Cell_ECM(std::string IDi, double capin, double SOCin)
Definition: Cell_ECM.hpp:52
double T() override
overwrite from Cell
Definition: Cell_ECM.hpp:63
Cell_ECM(std::string IDi)
Definition: Cell_ECM.hpp:58
Cell_ECM(std::string IDi, double capin, double SOCin, double Rdc_, std::array< double, N_RC > Rp_, std::array< double, N_RC > inv_tau_)
Definition: Cell_ECM.hpp:45
void timeStep_CC(double dt, int steps=1) override
take a number of time steps
Definition: Cell_ECM.hpp:334
double getThermalSurface() override
return the 'A' for the thermal model of this SU (Q = hA*dT)
Definition: Cell_ECM.hpp:76
void setT(double Tnew) override
functionality
Definition: Cell_ECM.hpp:83
Cell_ECM()
Definition: Cell_ECM.hpp:99
Status setSOC(double SOCnew, bool checkV=true, bool print=true) override
Definition: Cell_ECM.hpp:240
Status setVoltage(double Vnew, bool checkI=true, bool print=true) override
Definition: Cell_ECM.hpp:203
auto & getStateObj()
Definition: Cell_ECM.hpp:69
double V() override
crit is an optional argument
Definition: Cell_ECM.hpp:270
double I() const override
Definition: Cell_ECM.hpp:60
virtual bool validStates(bool print=true) override
checks if a state array is valid
Definition: Cell_ECM.hpp:307
std::array< double, N_RC > inv_tau
Definition: Cell_ECM.hpp:35
Status setStates(setStates_t s, bool checkStates=true, bool print=true) override
opposite of getStates, check the states are valid?
Definition: Cell_ECM.hpp:289
std::array< double, N_RC > Rp
Definition: Cell_ECM.hpp:35
XYdata_ff OCV
SOC vs voltage curve.
Definition: Cell_ECM.hpp:37
double Rdc
DC resistance [Ohm].
Definition: Cell_ECM.hpp:38
Status setCurrent(double Inew, bool checkV=true, bool print=true) override
Definition: Cell_ECM.hpp:182
void getStates(getStates_t s) override
returns one long array with the states
Definition: Cell_ECM.hpp:67
double SOC() override
Definition: Cell_ECM.hpp:62
Cell_ECM< N_RC > * copy() override
copy this SU to a new object
Definition: Cell_ECM.hpp:90
double getRtot() override
Return the total resistance, V = OCV - I*Rtot.
Definition: Cell_ECM.hpp:74
double getThotSpot() override
the T of the hottest element in the SU
Definition: Cell_ECM.hpp:75
double getOCV() override
Not implemented?
Definition: Cell_ECM.hpp:77
double getIr()
current through the parallel resistance
Definition: Cell_ECM.hpp:61
Abstract Class representing a single battery cell.
Definition: Cell.hpp:33
void setCapacity(double capacity)
Definition: Cell.hpp:48
std::string ID
identification string
Definition: StorageUnit.hpp:29
std::span< double > & setStates_t
To pass states to read, non-expandable container.
Definition: StorageUnit.hpp:32
std::vector< double > & getStates_t
To pass states to save, expandable container.
Definition: StorageUnit.hpp:33
double interp(double x_i, bool print=false, bool bound=true)
Definition: XYdata.hpp:64
auto check_SOC(double SOCnew, double SOC_min=0, double SOC_max=1)
Definition: free_functions.hpp:104
auto check_Cell_states(auto &su, bool checkV)
Definition: free_functions.hpp:118
constexpr bool storeCumulativeData
Definition: derived_settings.hpp:19
constexpr auto printCrit
threshold of verbose of when to print error messages for critical errors
Definition: derived_settings.hpp:30
constexpr double T_ENV
environmental temperature
Definition: settings.hpp:70
Slide namespace contains all the types, classes, and functions for the simulation framework.
Definition: Cell.hpp:27
bool isStatusBad(Status status)
Definition: Status.hpp:50
FixedData< double > linspace_fix(double x1, double x2, int N)
Definition: util.hpp:108
Status
Definition: Status.hpp:15
out SOC
Definition: squeeze_variables.m:15
out I
Definition: squeeze_variables.m:14
out V
Definition: squeeze_variables.m:16
State_ECM template class for holding the states of the ECM model.
Definition: State_ECM.hpp:20
Definition: State.hpp:24