A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
generic-battery-model.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2010 Andrea Sacco: Li-Ion battery
3 * Copyright (c) 2023 Tokushima University, Japan:
4 * NiMh,NiCd,LeaAcid batteries and preset and multicell extensions.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation;
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Author: Andrea Sacco <andrea.sacco85@gmail.com>
20 * Alberto Gallegos Ramonet <alramonet@is.tokushima-u.ac.jp>
21 */
22
24
25#include <ns3/assert.h>
26#include <ns3/double.h>
27#include <ns3/log.h>
28#include <ns3/simulator.h>
29#include <ns3/trace-source-accessor.h>
30
31#include <cmath>
32
33namespace ns3
34{
35namespace energy
36{
37
38NS_LOG_COMPONENT_DEFINE("GenericBatteryModel");
39NS_OBJECT_ENSURE_REGISTERED(GenericBatteryModel);
40
41TypeId
43{
44 static TypeId tid =
45 TypeId("ns3::GenericBatteryModel")
47 .SetGroupName("Energy")
48 .AddConstructor<GenericBatteryModel>()
49 .AddAttribute("LowBatteryThreshold",
50 "Low battery threshold for generic battery model.",
51 DoubleValue(0.10), // 0.10 as a fraction of the initial energy
53 MakeDoubleChecker<double>())
54 .AddAttribute("FullVoltage",
55 "(Q_full) The voltage of the cell when fully charged (V).",
56 DoubleValue(4.18),
58 MakeDoubleChecker<double>())
59 .AddAttribute("MaxCapacity",
60 "(Q) The maximum capacity of the cell (Ah).",
61 DoubleValue(2.45),
63 MakeDoubleChecker<double>())
64 .AddAttribute("NominalVoltage",
65 "(V_nom) Nominal voltage of the cell (V).",
66 DoubleValue(3.59),
68 MakeDoubleChecker<double>())
69 .AddAttribute("NominalCapacity",
70 "(Q_nom) Cell capacity at the end of the nominal zone (Ah)",
71 DoubleValue(1.3),
73 MakeDoubleChecker<double>())
74 .AddAttribute("ExponentialVoltage",
75 "(V_exp) Cell voltage at the end of the exponential zone (V).",
76 DoubleValue(3.75),
78 MakeDoubleChecker<double>())
79 .AddAttribute("ExponentialCapacity",
80 "(Q_exp) Cell Capacity at the end of the exponential zone (Ah).",
81 DoubleValue(0.39),
83 MakeDoubleChecker<double>())
84 .AddAttribute("InternalResistance",
85 "(R) Internal resistance of the cell (Ohms)",
86 DoubleValue(0.083),
88 MakeDoubleChecker<double>())
89 .AddAttribute("TypicalDischargeCurrent",
90 "Typical discharge current used in manufacturers datasheets (A)",
91 DoubleValue(2.33),
93 MakeDoubleChecker<double>())
94 .AddAttribute("CutoffVoltage",
95 "The voltage where the battery is considered depleted (V).",
96 DoubleValue(3.3),
98 MakeDoubleChecker<double>())
99 .AddAttribute("PeriodicEnergyUpdateInterval",
100 "Time between two consecutive periodic energy updates.",
101 TimeValue(Seconds(1.0)),
105 .AddAttribute("BatteryType",
106 "Indicates the battery type used by the model",
108 MakeEnumAccessor<GenericBatteryType>(&GenericBatteryModel::m_batteryType),
110 "LION_LIPO",
111 NIMH_NICD,
112 "NIMH_NICD",
113 LEADACID,
114 "LEADACID"))
115 .AddTraceSource("RemainingEnergy",
116 "Remaining energy of generic battery",
118 "ns3::TracedValueCallback::Double");
119 return tid;
120}
121
123 : m_drainedCapacity(0),
124 m_currentFiltered(0),
125 m_entn(0),
126 m_expZone(0),
127 m_lastUpdateTime(Seconds(0.0))
128{
129 NS_LOG_FUNCTION(this);
130}
131
133{
134 NS_LOG_FUNCTION(this);
135}
136
137double
139{
140 double initialEnergy = m_qMax * m_vFull * 3600;
141 return initialEnergy;
142}
143
144double
146{
147 return m_supplyVoltageV;
148}
149
150void
152{
153 NS_LOG_FUNCTION(this << interval);
154 m_energyUpdateInterval = interval;
155}
156
157void
159{
160 NS_ASSERT(drainedCapacity >= 0 && drainedCapacity < m_qMax);
161 m_drainedCapacity = drainedCapacity;
162}
163
164double
166{
167 return m_drainedCapacity;
168}
169
170double
172{
173 double soc = 100 * (1 - m_drainedCapacity / m_qMax);
174 return soc;
175}
176
177Time
179{
180 NS_LOG_FUNCTION(this);
182}
183
184double
186{
187 NS_LOG_FUNCTION(this);
189 return m_remainingEnergyJ;
190}
191
192double
194{
195 NS_LOG_FUNCTION(this);
196 return GetStateOfCharge();
197}
198
199void
201{
202 NS_LOG_FUNCTION(this);
203
204 // do not update if simulation has finished
206 {
207 return;
208 }
209
211
213
215
217 {
218 // check if battery is depleted
220 }
221 else if (m_supplyVoltageV >= m_vFull)
222 {
223 // check if battery has reached full charge
225 // TODO: Should battery charging be stopped if full voltage is reached?
226 // or should it be allowed to continue charging (overcharge)?
227 }
228
231}
232
233void
235{
236 NS_LOG_FUNCTION(this);
237}
238
239void
241{
242 NS_LOG_FUNCTION(this);
244}
245
246void
248{
249 NS_LOG_FUNCTION(this);
250 // notify DeviceEnergyModel objects, all "usable" energy has been depleted
251 // (cutoff voltage was reached)
253}
254
255void
257{
258 NS_LOG_FUNCTION(this);
259 // notify DeviceEnergyModel objects, the battery has reached its full energy potential.
260 // (full voltage was reached)
262}
263
264void
266{
267 NS_LOG_FUNCTION(this);
268
269 double totalCurrentA = CalculateTotalCurrent();
270
272
274
275 // Calculate i* (current step response)
276 Time batteryResponseConstant = Seconds(30);
277
278 double responseTime = (Simulator::Now() / batteryResponseConstant).GetDouble();
279 m_currentFiltered = totalCurrentA * (1 - 1 / (std::exp(responseTime)));
280 // TODO: the time in the responseTime should be a time taken since the last *battery current*
281 // change, in the testing the battery current is only changed at the beginning of the
282 // simulation therefore, the simulation time can be used. However this must be changed to
283 // a time counter to allow this value to reset in the middle of the simulation when the
284 // battery current changes.
285
286 m_drainedCapacity += (totalCurrentA * m_energyUpdateLapseTime).GetHours();
287
288 if (totalCurrentA < 0)
289 {
290 // Charge current (Considered as "Negative" i)
291 m_supplyVoltageV = GetChargeVoltage(totalCurrentA);
292 }
293 else
294 {
295 // Discharge current (Considered as "Positive" i)
296 m_supplyVoltageV = GetVoltage(totalCurrentA);
297 }
298}
299
300double
302{
303 // integral of i over time drained capacity in Ah
304 double it = m_drainedCapacity;
305
306 // empirical factors
307 double A = m_vFull - m_vExp;
308 double B = 3 / m_qExp;
309
310 // voltage constant
312
313 // voltage of exponential zone when battery is fully charged
314 double expZoneFull = A * std::exp(-B * m_qNom);
315
316 // Obtain the voltage|resistance polarization constant
317 double K = (E0 - m_vNom - (m_internalResistance * m_typicalCurrent) + expZoneFull) /
319
320 double V = 0;
321 double polResistance = 0;
322 double polVoltage = 0;
323
325 { // For LiOn & LiPo batteries
326
327 // Calculate exponential zone voltage
328 m_expZone = A * std::exp(-B * it);
329
330 polResistance = K * m_qMax / (it + 0.1 * m_qMax);
331 polVoltage = K * m_qMax / (m_qMax - it);
332 V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) -
333 (polVoltage * it) + m_expZone;
334 }
335 else
336 {
337 // Calculate exponential zone voltage
338
339 if (m_expZone == 0)
340 {
341 m_expZone = A * std::exp(-B * it);
342 }
343 double entnPrime = m_entn;
344 double expZonePrime = m_expZone;
345 m_entn = B * std::abs(i) * (-expZonePrime + A);
346 m_expZone = expZonePrime + (m_energyUpdateLapseTime * entnPrime).GetHours();
347
349 { // For NiMH and NiCd batteries
350 polResistance = K * m_qMax / (std::abs(it) + 0.1 * m_qMax);
351 }
352 else if (m_batteryType == LEADACID)
353 { // For Lead acid batteries
354 polResistance = K * m_qMax / (it + 0.1 * m_qMax);
355 }
356
357 polVoltage = K * m_qMax / (m_qMax - it);
358
359 V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) -
360 (polVoltage * it) + m_expZone;
361 }
362
363 // Energy in Joules = RemainingCapacity * Voltage * Seconds in an Hour
364 m_remainingEnergyJ = (m_qMax - it) * V * 3600;
365
366 NS_LOG_DEBUG("* CHARGE *| " << Simulator::Now().As(Time::S) << "| i " << i << " | it " << it
367 << "| E0 " << E0 << " | polRes " << polResistance << " | polVol "
368 << polVoltage << "| B " << B << " | ExpZone " << m_expZone
369 << " | A " << A << "| K " << K << "| i* " << m_currentFiltered
370 << " | V " << V << " | rmnEnergy " << m_remainingEnergyJ
371 << "J | SoC " << GetStateOfCharge() << "% ");
372
373 return V;
374}
375
376double
378{
379 NS_LOG_FUNCTION(this << i);
380
381 // integral of i in dt, drained capacity in Ah
382 double it = m_drainedCapacity;
383
384 // empirical factors
385 double A = m_vFull - m_vExp;
386
387 double B = 3 / m_qExp;
388
389 // constant voltage
391
392 // voltage of exponential zone when battery is fully charged
393 double expZoneFull = A * std::exp(-B * m_qNom);
394
395 // Obtain the voltage|resistance polarization constant
396 double K = (E0 - m_vNom - (m_internalResistance * m_typicalCurrent) + expZoneFull) /
398
399 double V = 0;
400 double polResistance = K * (m_qMax / (m_qMax - it));
401 double polVoltage = polResistance;
402
403 // Calculate exponential zone voltage according to the battery type
405 {
406 m_expZone = A * exp(-B * it);
407 }
408 else
409 {
411 if (m_expZone == 0)
412 {
413 m_expZone = A * exp(-B * it);
414 }
415
416 double entnPrime = m_entn;
417 double expZonePrime = m_expZone;
418
419 m_entn = B * std::abs(i) * (-expZonePrime);
420 m_expZone = expZonePrime + (m_energyUpdateLapseTime * entnPrime).GetHours();
421 }
422
423 V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) - (polVoltage * it) +
424 m_expZone;
425
426 // EnergyJ = RemainingCapacity * Voltage * Seconds in an Hour
427 m_remainingEnergyJ = (m_qMax - it) * V * 3600;
428
429 NS_LOG_DEBUG("* DISCHARGE *| " << Simulator::Now().As(Time::S) << "| i " << i << " | it " << it
430 << " | A " << A << " | B " << B << " | ExpZone " << m_expZone
431 << " | V " << V << " | rmnEnergy " << m_remainingEnergyJ
432 << "J | SoC " << GetStateOfCharge() << "% "
433 << "\n"
434 << " | K " << K << " | E0 " << E0);
435
436 return V;
437}
438
439} // namespace energy
440} // namespace ns3
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
Hold variables of type enum.
Definition: enum.h:62
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:55
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition: simulator.h:571
static bool IsFinished()
Check if the simulation should finish.
Definition: simulator.cc:171
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
double GetSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:403
@ S
second
Definition: nstime.h:116
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
Energy source base class.
Definition: energy-source.h:88
void BreakDeviceEnergyModelRefCycle()
This function is called to break reference cycle between EnergySource and DeviceEnergyModel.
void NotifyEnergyDrained()
This function notifies all DeviceEnergyModel of energy depletion event.
void NotifyEnergyRecharged()
This function notifies all DeviceEnergyModel of energy recharged event.
A generic battery model for Li-Ion, NiCd, NiMh and Lead acid batteries.
void DoDispose() override
All child's implementation must call BreakDeviceEnergyModelRefCycle to ensure reference cycles to Dev...
double m_expZone
Voltage value of the exponential zone.
double m_cutoffVoltage
The threshold voltage where the battery is considered depleted.
double GetChargeVoltage(double current)
Obtain the battery voltage as a result of a charge current.
static TypeId GetTypeId()
Get the type ID.
void BatteryChargedEvent()
Handles the battery reaching its full voltage.
double GetEnergyFraction() override
Implements GetEnergyFraction.
EventId m_energyUpdateEvent
Energy update event.
double m_lowBatteryTh
Low battery threshold, as a fraction of the initial energy.
double m_currentFiltered
The step response (a.k.a.
Time m_energyUpdateLapseTime
The lapse of time between the last battery energy update and the current time.
double m_qMax
The maximum capacity of the battery, in Ah.
double m_supplyVoltageV
Actual voltage of the battery.
double m_qNom
Battery capacity at the end of the nominal zone, in Ah.
double m_drainedCapacity
Capacity drained from the battery, in Ah.
double m_vFull
Initial voltage of the battery, in Volts.
double m_entn
The previous value of the exponential zone in NiMh,NiCd and LeadAcid.
double m_qExp
Capacity value at the end of the exponential zone, in Ah.
void SetDrainedCapacity(double drainedCapacity)
This function is used to change the initial capacity in the battery.
double GetSupplyVoltage() const override
Implements GetSupplyVoltage.
TracedValue< double > m_remainingEnergyJ
Remaining energy, in Joules.
double GetRemainingEnergy() override
Implements GetRemainingEnergy.
void BatteryDepletedEvent()
Handles the battery reaching its cutoff voltage.
double GetVoltage(double current)
Get the battery voltage in function of the discharge current.
double m_typicalCurrent
Typical discharge current used to fit the curves.
GenericBatteryType m_batteryType
Indicates the battery type used by the model.
void DoInitialize() override
Initialize() implementation.
double GetStateOfCharge() const
Calculates an estimate of the State of Charge (SoC).
double GetInitialEnergy() const override
Implements GetInitialEnergy.
double m_vNom
Nominal voltage of the battery, in Volts.
double GetDrainedCapacity() const
Obtain the amount of drained capacity from the battery based on the integral of the current over time...
void CalculateRemainingEnergy()
Calculates remaining energy.
void UpdateEnergySource() override
Implements UpdateEnergySource.
double m_vExp
Battery voltage at the end of the exponential zone, in Volts.
void SetEnergyUpdateInterval(Time interval)
This function sets the interval between each energy update.
double m_internalResistance
Internal resistance of the battery, in Ohms.
Time m_energyUpdateInterval
Energy update interval.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
@ LEADACID
Lead Acid Batteries.
@ NIMH_NICD
Nickel-metal hydride and Nickel cadmium batteries.
@ LION_LIPO
Lithium-ion and Lithium-polymer batteries.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1319
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
Ptr< const AttributeChecker > MakeEnumChecker(T v, std::string n, Ts... args)
Make an EnumChecker pre-configured with a set of allowed values by name.
Definition: enum.h:189
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427