Skip to content

Commit

Permalink
Merge pull request #176 from nasa/37-simplified-equivalent-circuit-ba…
Browse files Browse the repository at this point in the history
…ttery-model

Add simplified battery model from tutorial
  • Loading branch information
teubert authored Nov 13, 2024
2 parents 74d74ce + 6ef9eab commit 85e2e39
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
4 changes: 4 additions & 0 deletions sphinx-config/api_ref/progpy/IncludedModels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Battery Model

.. autoclass:: progpy.models.BatteryElectroChemEODEOL

.. tab:: Simplified

.. autoclass:: progpy.models.SimplifiedBattery

.. tab:: Circuit

.. autoclass:: progpy.models.BatteryCircuit
Expand Down
1 change: 1 addition & 0 deletions src/progpy/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from progpy.models.battery_circuit import BatteryCircuit
from progpy.models.battery_electrochem import BatteryElectroChem, BatteryElectroChemEOD, BatteryElectroChemEOL, BatteryElectroChemEODEOL
from progpy.models.battery_simplified import SimplifiedBattery
from progpy.models.centrifugal_pump import CentrifugalPump, CentrifugalPumpBase, CentrifugalPumpWithWear
from progpy.models.pneumatic_valve import PneumaticValve, PneumaticValveBase, PneumaticValveWithWear
from progpy.models.dcmotor import DCMotor
Expand Down
107 changes: 107 additions & 0 deletions src/progpy/models/battery_simplified.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Copyright © 2021 United States Government as represented by the Administrator of the
# National Aeronautics and Space Administration. All Rights Reserved.

import math
from progpy import PrognosticsModel

def update_x0(params):
return {'x0':
{
'SOC': params['x0']['SOC'],
'v': params['v_L']}}


class SimplifiedBattery(PrognosticsModel):
"""
.. versionadded:: 1.8.0
Simplified battery model from [Sierra2019]_. Introduced in 2024 PHM Society Tutorial.
:term:`Events<event>`: (2)
EOD: End of Discharge (Complete)
Low V: When voltage hits a specified threshold (VEOD)
:term:`Inputs/Loading<input>`: (1)
P: Power draw on the battery
:term:`States<state>`: (2)
| SOC: State of Charge
| v: Voltage supplied by battery
:term:`Outputs<output>`: (1)
v: Voltage supplied by battery
Keyword Args
------------
process_noise : Optional, float or dict[str, float]
:term:`Process noise<process noise>` (applied at dx/next_state).
Can be number (e.g., .2) applied to every state, a dictionary of values for each
state (e.g., {'x1': 0.2, 'x2': 0.3}), or a function (x) -> x
process_noise_dist : Optional, str
distribution for :term:`process noise` (e.g., normal, uniform, triangular)
measurement_noise : Optional, float or dict[str, float]
:term:`Measurement noise<measurement noise>` (applied in output eqn).
Can be number (e.g., .2) applied to every output, a dictionary of values for each
output (e.g., {'z1': 0.2, 'z2': 0.3}), or a function (z) -> z
measurement_noise_dist : Optional, str
distribution for :term:`measurement noise` (e.g., normal, uniform, triangular)
Note
---------
Default parameters are for a Tattu battery.
References
-----------
.. [Sierra2019] G. Sierra and M. Orchard and K. Goebel and C. Kulkarni, "Battery health management for small-size rotary-wing electric unmanned aerial vehicles: An efficient approach for constrained computing platforms," Reliability Engineering & System Safety, Volume 182,2019. https://www.sciencedirect.com/science/article/pii/S0951832018301406
"""

inputs = ['P']
states = ['SOC', 'v']
outputs = ['v']
events = ['EOD', 'Low V']

state_limits = {
'SOC': (0.0, 1.0),
'v': (0, float('inf'))
}

default_parameters = {
'E_crit': 202426.858,
'v_L': 11.148,
'lambda': 0.046,
'gamma': 3.355,
'mu': 2.759,
'beta': 8.482,
'R_int': 0.027,
'VEOD': 9,

'x0': {
'SOC': 1,
'v': 11.148
}
}

param_callbacks = {
'v_L': [update_x0]
}

def next_state(self, x, u, dt):
x['SOC'] = x['SOC'] - u['P'] * dt / self['E_crit']

v_oc = self['v_L'] - self['lambda']**(self['gamma']*x['SOC']) - self['mu'] * math.exp(-self['beta']* math.sqrt(x['SOC']))
i = (v_oc - math.sqrt(v_oc**2 - 4 * self['R_int'] * u['P']))/(2 * self['R_int'])
v = v_oc - i * self['R_int']

x['v'] = v

return x

def output(self, x):
return self.OutputContainer({
'v': x['v']})

def event_state(self, x):
return {
'EOD': x['SOC'],
'Low V': (x['v'] - self['VEOD'])/(self['v_L'] - self['VEOD'])
}
11 changes: 10 additions & 1 deletion tests/test_battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys
import unittest

from progpy.models import BatteryCircuit, BatteryElectroChem, BatteryElectroChemEOL, BatteryElectroChemEOD, BatteryElectroChemEODEOL
from progpy.models import BatteryCircuit, BatteryElectroChem, BatteryElectroChemEOL, BatteryElectroChemEOD, BatteryElectroChemEODEOL, SimplifiedBattery
from progpy.loading import Piecewise

# Variable (piece-wise) future loading scheme
Expand All @@ -13,6 +13,11 @@
[600, 900, 1800, 3000, float('inf')],
{'i': [2, 1, 4, 2, 3]})

future_loading_power = Piecewise(
dict,
[600, 900, 1800, 3000, float('inf')],
{'P': [25, 12, 50, 25, 33]})


class TestBattery(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -45,6 +50,10 @@ def test_battery_electrochem_EOD(self):
batt = BatteryElectroChemEOD()
result = batt.simulate_to(200, future_loading, {'t': 18.95, 'v': 4.183})

def test_battery_simplified(self):
batt = SimplifiedBattery()
result = batt.simulate_to(200, future_loading_power, {'v': 4.183})

def test_battery_electrochem_EOL(self):
batt = BatteryElectroChemEOL()
(times, inputs, states, outputs, event_states) = batt.simulate_to(200, future_loading, {'t': 18.95, 'v': 4.183})
Expand Down

0 comments on commit 85e2e39

Please sign in to comment.