A Discrete-Event Network Simulator
API
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 
23 #include "generic-battery-model.h"
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 
33 namespace ns3
34 {
35 
36 NS_LOG_COMPONENT_DEFINE("GenericBatteryModel");
37 
38 NS_OBJECT_ENSURE_REGISTERED(GenericBatteryModel);
39 
40 TypeId
42 {
43  static TypeId tid =
44  TypeId("ns3::GenericBatteryModel")
46  .SetGroupName("Energy")
47  .AddConstructor<GenericBatteryModel>()
48  .AddAttribute("LowBatteryThreshold",
49  "Low battery threshold for generic battery model.",
50  DoubleValue(0.10), // 0.10 as a fraction of the initial energy
52  MakeDoubleChecker<double>())
53  .AddAttribute("FullVoltage",
54  "(Q_full) The voltage of the cell when fully charged (V).",
55  DoubleValue(4.18),
57  MakeDoubleChecker<double>())
58  .AddAttribute("MaxCapacity",
59  "(Q) The maximum capacity of the cell (Ah).",
60  DoubleValue(2.45),
62  MakeDoubleChecker<double>())
63  .AddAttribute("NominalVoltage",
64  "(V_nom) Nominal voltage of the cell (V).",
65  DoubleValue(3.59),
67  MakeDoubleChecker<double>())
68  .AddAttribute("NominalCapacity",
69  "(Q_nom) Cell capacity at the end of the nominal zone (Ah)",
70  DoubleValue(1.3),
72  MakeDoubleChecker<double>())
73  .AddAttribute("ExponentialVoltage",
74  "(V_exp) Cell voltage at the end of the exponential zone (V).",
75  DoubleValue(3.75),
77  MakeDoubleChecker<double>())
78  .AddAttribute("ExponentialCapacity",
79  "(Q_exp) Cell Capacity at the end of the exponential zone (Ah).",
80  DoubleValue(0.39),
82  MakeDoubleChecker<double>())
83  .AddAttribute("InternalResistance",
84  "(R) Internal resistance of the cell (Ohms)",
85  DoubleValue(0.083),
87  MakeDoubleChecker<double>())
88  .AddAttribute("TypicalDischargeCurrent",
89  "Typical discharge current used in manufacters datasheets (A)",
90  DoubleValue(2.33),
92  MakeDoubleChecker<double>())
93  .AddAttribute("CutoffVoltage",
94  "The voltage where the battery is considered depleted (V).",
95  DoubleValue(3.3),
97  MakeDoubleChecker<double>())
98  .AddAttribute("PeriodicEnergyUpdateInterval",
99  "Time between two consecutive periodic energy updates.",
100  TimeValue(Seconds(1.0)),
103  MakeTimeChecker())
104  .AddAttribute("BatteryType",
105  "Indicates the battery type used by the model",
107  MakeEnumAccessor<GenericBatteryType>(&GenericBatteryModel::m_batteryType),
109  "LION_LIPO",
110  NIMH_NICD,
111  "NIMH_NICD",
112  LEADACID,
113  "LEADACID"))
114  .AddTraceSource("RemainingEnergy",
115  "Remaining energy of generic battery",
117  "ns3::TracedValueCallback::Double");
118  return tid;
119 }
120 
122  : m_drainedCapacity(0),
123  m_currentFiltered(0),
124  m_entn(0),
125  m_expZone(0),
126  m_lastUpdateTime(Seconds(0.0))
127 {
128  NS_LOG_FUNCTION(this);
129 }
130 
132 {
133  NS_LOG_FUNCTION(this);
134 }
135 
136 double
138 {
139  double initialEnergy = m_qMax * m_vFull * 3600;
140  return initialEnergy;
141 }
142 
143 double
145 {
146  return m_supplyVoltageV;
147 }
148 
149 void
151 {
152  NS_LOG_FUNCTION(this << interval);
153  m_energyUpdateInterval = interval;
154 }
155 
156 void
158 {
159  NS_ASSERT(drainedCapacity >= 0 && drainedCapacity < m_qMax);
160  m_drainedCapacity = drainedCapacity;
161 }
162 
163 double
165 {
166  return m_drainedCapacity;
167 }
168 
169 double
171 {
172  double soc = 100 * (1 - m_drainedCapacity / m_qMax);
173  return soc;
174 }
175 
176 Time
178 {
179  NS_LOG_FUNCTION(this);
180  return m_energyUpdateInterval;
181 }
182 
183 double
185 {
186  NS_LOG_FUNCTION(this);
188  return m_remainingEnergyJ;
189 }
190 
191 double
193 {
194  NS_LOG_FUNCTION(this);
195  return GetStateOfCharge();
196 }
197 
198 void
200 {
201  NS_LOG_FUNCTION(this);
202 
203  // do not update if simulation has finished
204  if (Simulator::IsFinished())
205  {
206  return;
207  }
208 
210 
212 
214 
216  {
217  // check if battery is depleted
219  }
220  else if (m_supplyVoltageV >= m_vFull)
221  {
222  // check if battery has reached full charge
224  // TODO: Should battery charging be stopped if full voltage is reached?
225  // or should it be allowed to continue charging (overcharge)?
226  }
227 
230 }
231 
232 void
234 {
235  NS_LOG_FUNCTION(this);
236 }
237 
238 void
240 {
241  NS_LOG_FUNCTION(this);
243 }
244 
245 void
247 {
248  NS_LOG_FUNCTION(this);
249  // notify DeviceEnergyModel objects, all "usable" energy has been depleted
250  // (cutoff voltage was reached)
252 }
253 
254 void
256 {
257  NS_LOG_FUNCTION(this);
258  // notify DeviceEnergyModel objects, the battery has reached its full energy potential.
259  // (full voltage was reached)
261 }
262 
263 void
265 {
266  NS_LOG_FUNCTION(this);
267 
268  double totalCurrentA = CalculateTotalCurrent();
269 
271 
273 
274  // Calculate i* (current step response)
275  Time batteryResponseConstant = Seconds(30);
276 
277  double responseTime = (Simulator::Now() / batteryResponseConstant).GetDouble();
278  m_currentFiltered = totalCurrentA * (1 - 1 / (std::exp(responseTime)));
279  // TODO: the time in the responseTime should be a time taken since the last *battery current*
280  // change, in the testing the battery current is only changed at the beginning of the
281  // simulation therefore, the simulation time can be used. However this must be changed to
282  // a time counter to allow this value to reset in the middle of the simulation when the
283  // battery current changes.
284 
285  m_drainedCapacity += (totalCurrentA * m_energyUpdateLapseTime).GetHours();
286 
287  if (totalCurrentA < 0)
288  {
289  // Charge current (Considered as "Negative" i)
290  m_supplyVoltageV = GetChargeVoltage(totalCurrentA);
291  }
292  else
293  {
294  // Discharge current (Considered as "Positive" i)
295  m_supplyVoltageV = GetVoltage(totalCurrentA);
296  }
297 }
298 
299 double
301 {
302  // integral of i over time drained capacity in Ah
303  double it = m_drainedCapacity;
304 
305  // empirical factors
306  double A = m_vFull - m_vExp;
307  double B = 3 / m_qExp;
308 
309  // voltage constant
310  double E0 = m_vFull + m_internalResistance * m_typicalCurrent - A;
311 
312  // voltage of exponential zone when battery is fully charged
313  double expZoneFull = A * std::exp(-B * m_qNom);
314 
315  // Obtain the voltage|resistance polarization constant
316  double K = (E0 - m_vNom - (m_internalResistance * m_typicalCurrent) + expZoneFull) /
318 
319  double V = 0;
320  double polResistance = 0;
321  double polVoltage = 0;
322 
323  if (m_batteryType == LION_LIPO)
324  { // For LiOn & LiPo batteries
325 
326  // Calculate exponential zone voltage
327  m_expZone = A * std::exp(-B * it);
328 
329  polResistance = K * m_qMax / (it + 0.1 * m_qMax);
330  polVoltage = K * m_qMax / (m_qMax - it);
331  V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) -
332  (polVoltage * it) + m_expZone;
333  }
334  else
335  {
336  // Calculate exponential zone voltage
337 
338  if (m_expZone == 0)
339  {
340  m_expZone = A * std::exp(-B * it);
341  }
342  double entnPrime = m_entn;
343  double expZonePrime = m_expZone;
344  m_entn = B * std::abs(i) * (-expZonePrime + A);
345  m_expZone = expZonePrime + (m_energyUpdateLapseTime * entnPrime).GetHours();
346 
347  if (m_batteryType == NIMH_NICD)
348  { // For NiMH and NiCd batteries
349  polResistance = K * m_qMax / (std::abs(it) + 0.1 * m_qMax);
350  }
351  else if (m_batteryType == LEADACID)
352  { // For Lead acid batteries
353  polResistance = K * m_qMax / (it + 0.1 * m_qMax);
354  }
355 
356  polVoltage = K * m_qMax / (m_qMax - it);
357 
358  V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) -
359  (polVoltage * it) + m_expZone;
360  }
361 
362  // Energy in Joules = RemainingCapacity * Voltage * Seconds in an Hour
363  m_remainingEnergyJ = (m_qMax - it) * V * 3600;
364 
365  NS_LOG_DEBUG("* CHARGE *| " << Simulator::Now().As(Time::S) << "| i " << i << " | it " << it
366  << "| E0 " << E0 << " | polRes " << polResistance << " | polVol "
367  << polVoltage << "| B " << B << " | ExpZone " << m_expZone
368  << " | A " << A << "| K " << K << "| i* " << m_currentFiltered
369  << " | V " << V << " | rmnEnergy " << m_remainingEnergyJ
370  << "J | SoC " << GetStateOfCharge() << "% ");
371 
372  return V;
373 }
374 
375 double
377 {
378  NS_LOG_FUNCTION(this << i);
379 
380  // integral of i in dt, drained capacity in Ah
381  double it = m_drainedCapacity;
382 
383  // empirical factors
384  double A = m_vFull - m_vExp;
385 
386  double B = 3 / m_qExp;
387 
388  // constant voltage
389  double E0 = m_vFull + m_internalResistance * m_typicalCurrent - A;
390 
391  // voltage of exponential zone when battery is fully charged
392  double expZoneFull = A * std::exp(-B * m_qNom);
393 
394  // Obtain the voltage|resistance polarization constant
395  double K = (E0 - m_vNom - (m_internalResistance * m_typicalCurrent) + expZoneFull) /
397 
398  double V = 0;
399  double polResistance = K * (m_qMax / (m_qMax - it));
400  double polVoltage = polResistance;
401 
402  // Calculate exponential zone voltage according to the battery type
403  if (m_batteryType == LION_LIPO)
404  {
405  m_expZone = A * exp(-B * it);
406  }
407  else
408  {
410  if (m_expZone == 0)
411  {
412  m_expZone = A * exp(-B * it);
413  }
414 
415  double entnPrime = m_entn;
416  double expZonePrime = m_expZone;
417 
418  m_entn = B * std::abs(i) * (-expZonePrime);
419  m_expZone = expZonePrime + (m_energyUpdateLapseTime * entnPrime).GetHours();
420  }
421 
422  V = E0 - (m_internalResistance * i) - (polResistance * m_currentFiltered) - (polVoltage * it) +
423  m_expZone;
424 
425  // EnergyJ = RemainingCapacity * Voltage * Seconds in an Hour
426  m_remainingEnergyJ = (m_qMax - it) * V * 3600;
427 
428  NS_LOG_DEBUG("* DISCHARGE *| " << Simulator::Now().As(Time::S) << "| i " << i << " | it " << it
429  << " | A " << A << " | B " << B << " | ExpZone " << m_expZone
430  << " | V " << V << " | rmnEnergy " << m_remainingEnergyJ
431  << "J | SoC " << GetStateOfCharge() << "% "
432  << "\n"
433  << " | K " << K << " | E0 " << E0);
434 
435  return V;
436 }
437 
438 } // namespace ns3
This class can be used to hold variables of floating point type such as 'double' or 'float'.
Definition: double.h:42
double CalculateTotalCurrent()
void NotifyEnergyRecharged()
This function notifies all DeviceEnergyModel of energy recharged event.
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.
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
A generic battery model for Li-Ion, NiCd, NiMh and Lead acid batteries.
double m_entn
The previous value of the exponential zone in NiMh,NiCd and LeadAcid.
double m_expZone
Voltage value of the exponential zone.
void BatteryChargedEvent()
Handles the battery reaching its full voltage.
double GetEnergyFraction() override
Implements GetEnergyFraction.
Time m_lastUpdateTime
Last update time.
double m_lowBatteryTh
Low battery threshold, as a fraction of the initial energy.
double m_typicalCurrent
Typical discharge current used to fit the curves.
double GetStateOfCharge() const
Calculates an estimate of the State of Charge (SoC).
double GetDrainedCapacity() const
Obtain the amount of drained capacity from the battery based on the integral of the current over time...
Time m_energyUpdateInterval
Energy update interval.
void UpdateEnergySource() override
Implements UpdateEnergySource.
double m_currentFiltered
The step response (a.k.a.
double m_qMax
The maximum capacity of the battery, in Ah.
void CalculateRemainingEnergy()
Calculates remaining energy.
double GetVoltage(double current)
Get the battery voltage in function of the discharge current.
void DoInitialize() override
Initialize() implementation.
double m_vExp
Battery voltage at the end of the exponential zone, in Volts.
TracedValue< double > m_remainingEnergyJ
Remaining energy, in Joules.
double GetSupplyVoltage() const override
Implements GetSupplyVoltage.
double m_vNom
Nominal voltage of the battery, in Volts.
EventId m_energyUpdateEvent
Energy update event.
double GetChargeVoltage(double current)
Obtain the battery voltage as a result of a charge current.
double GetRemainingEnergy() override
Implements GetRemainingEnergy.
double m_internalResistance
Internal resistance of the battery, in Ohms.
void SetEnergyUpdateInterval(Time interval)
This function sets the interval between each energy update.
void DoDispose() override
All child's implementation must call BreakDeviceEnergyModelRefCycle to ensure reference cycles to Dev...
GenericBatteryType m_batteryType
Indicates the battery type used by the model.
double m_qNom
Battery capacity at the end of the nominal zone, in Ah.
static TypeId GetTypeId()
Get the type ID.
double m_vFull
Initial voltage of the battery, in Volts.
double m_drainedCapacity
Capacity drained from the battery, in Ah.
Time m_energyUpdateLapseTime
The lapse of time between the last battery energy update and the current time.
double m_cutoffVoltage
The threshold voltage where the battery is considered depleted.
void SetDrainedCapacity(double drainedCapacity)
This function is used to change the initial capacity in the battery.
double m_qExp
Capacity value at the end of the exponential zone, in Ah.
void BatteryDepletedEvent()
Handles the battery reaching its cutoff voltage.
double GetInitialEnergy() const override
Implements GetInitialEnergy.
double m_supplyVoltageV
Actual voltage of the battery.
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:931
#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
@ NIMH_NICD
Nickel-metal hydride and Nickel cadmium batteries.
@ LION_LIPO
Lithium-ion and Lithium-polymer batteries.
@ LEADACID
Lead Acid 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:1326
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:1414
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:194
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:533
Ptr< const AttributeAccessor > MakeDoubleAccessor(T1 a1)
Definition: double.h:43