Skip to content

Commit

Permalink
Merge pull request #527 from suavecode/feature-battery_charge
Browse files Browse the repository at this point in the history
fixed battery for solar UAV
  • Loading branch information
planes committed Nov 6, 2021
2 parents 1dde88f + 4e42755 commit 5bc7427
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 39 deletions.
2 changes: 1 addition & 1 deletion regression/scripts/solar_network/solar_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def main():
truth_F = 105.36115293829462
truth_rpm = 218.18739964349612
truth_i = 130.17994767726535
truth_bat = 548777403.1018918
truth_bat = 136537368.1714456

print('battery energy')
print(energy)
Expand Down
2 changes: 1 addition & 1 deletion regression/scripts/solar_network/solar_uav_mission.res

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def add_unknowns_and_residuals_to_segment(self, segment, initial_voltage = None,
battery = self.battery

# Assign initial segment conditions to segment if missing
append_initial_battery_conditions(segment)
append_initial_battery_conditions(segment,battery)

segment.state.residuals.network = Residuals()

Expand Down
4 changes: 2 additions & 2 deletions trunk/SUAVE/Components/Energy/Networks/Battery_Propeller.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,11 +412,11 @@ def add_unknowns_and_residuals_to_segment(self, segment, initial_voltage = None,
n_props = 1

# Assign initial segment conditions to segment if missing
append_initial_battery_conditions(segment)
battery = self.battery
append_initial_battery_conditions(segment,battery)

# add unknowns and residuals specific to battery cell
segment.state.residuals.network = Residuals()
battery = self.battery
battery.append_battery_unknowns_and_residuals_to_segment(segment,initial_voltage,
initial_battery_cell_temperature , initial_battery_state_of_charge,
initial_battery_cell_current)
Expand Down
12 changes: 6 additions & 6 deletions trunk/SUAVE/Components/Energy/Networks/Lift_Cruise.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,11 +730,11 @@ def add_transition_unknowns_and_residuals_to_segment(self, segment, initial_volt
self.number_of_lift_rotor_engines = int(self.number_of_lift_rotor_engines)

# Assign initial segment conditions to segment if missing
append_initial_battery_conditions(segment)
battery = self.battery
append_initial_battery_conditions(segment,battery)

# add unknowns and residuals specific to battery cell
segment.state.residuals.network = Residuals()
battery = self.battery
battery.append_battery_unknowns_and_residuals_to_segment(segment,initial_voltage, initial_battery_cell_temperature ,
initial_battery_state_of_charge, initial_battery_cell_current)
if segment.battery_discharge:
Expand Down Expand Up @@ -824,11 +824,11 @@ def add_cruise_unknowns_and_residuals_to_segment(self, segment, initial_voltage
self.number_of_lift_rotor_engines = int(self.number_of_lift_rotor_engines)

# Assign initial segment conditions to segment if missing
append_initial_battery_conditions(segment)
battery = self.battery
append_initial_battery_conditions(segment,battery)

# add unknowns and residuals specific to to battery cell
segment.state.residuals.network = Residuals()
battery = self.battery
battery.append_battery_unknowns_and_residuals_to_segment(segment,initial_voltage, initial_battery_cell_temperature ,
initial_battery_state_of_charge, initial_battery_cell_current)
if segment.battery_discharge:
Expand Down Expand Up @@ -920,11 +920,11 @@ def add_lift_unknowns_and_residuals_to_segment(self, segment, initial_voltage =
self.number_of_lift_rotor_engines = int(self.number_of_lift_rotor_engines)

# Assign initial segment conditions to segment if missing
append_initial_battery_conditions(segment)
battery = self.battery
append_initial_battery_conditions(segment,battery)

# add unknowns and residuals specific to battery cell
segment.state.residuals.network = Residuals()
battery = self.battery
battery.append_battery_unknowns_and_residuals_to_segment(segment,initial_voltage, initial_battery_cell_temperature ,
initial_battery_state_of_charge, initial_battery_cell_current)
if segment.battery_discharge:
Expand Down
38 changes: 22 additions & 16 deletions trunk/SUAVE/Components/Energy/Networks/Solar.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ def evaluate_thrust(self,state):
# Unpack conditions
a = conditions.freestream.speed_of_sound


# Set battery energy
battery.current_energy = conditions.propulsion.battery_energy
battery.pack_temperature = conditions.propulsion.battery_pack_temperature
Expand Down Expand Up @@ -188,7 +187,7 @@ def evaluate_thrust(self,state):
F[eta[:,0]>1.0,:] = F[eta[:,0]>1.0,:]*eta[eta[:,0]>1.0,:]

# Run the motor for current
motor.current(conditions)
_ , etam = motor.current(conditions)

# Conditions specific to this instantation of motor and propellers
R = prop.tip_radius
Expand All @@ -199,13 +198,16 @@ def evaluate_thrust(self,state):
total_motor_current = total_motor_current + factor*motor.outputs.current

# Pack specific outputs
conditions.propulsion.propeller_motor_torque[:,ii] = motor.outputs.torque[:,0]
conditions.propulsion.propeller_torque[:,ii] = Q[:,0]
conditions.propulsion.propeller_rpm[:,ii] = rpm[:,0]
conditions.propulsion.propeller_tip_mach[:,ii] = (R*rpm[:,0]*Units.rpm)/a[:,0]
conditions.propulsion.disc_loading[:,ii] = (F_mag[:,0])/(np.pi*(R**2)) # N/m^2
conditions.propulsion.power_loading[:,ii] = (F_mag[:,0])/(P[:,0]) # N/W
conditions.noise.sources.propellers[prop.tag] = outputs
conditions.propulsion.propeller_motor_efficiency[:,ii] = etam[:,0]
conditions.propulsion.propeller_motor_torque[:,ii] = motor.outputs.torque[:,0]
conditions.propulsion.propeller_torque[:,ii] = Q[:,0]
conditions.propulsion.propeller_thrust[:,ii] = np.linalg.norm(total_thrust ,axis = 1)
conditions.propulsion.propeller_rpm[:,ii] = rpm[:,0]
conditions.propulsion.propeller_tip_mach[:,ii] = (R*rpm[:,0]*Units.rpm)/a[:,0]
conditions.propulsion.disc_loading[:,ii] = (F_mag[:,0])/(np.pi*(R**2)) # N/m^2
conditions.propulsion.power_loading[:,ii] = (F_mag[:,0])/(P[:,0]) # N/W
conditions.propulsion.propeller_efficiency[:,ii] = etap[:,0]
conditions.noise.sources.propellers[prop.tag] = outputs

# Run the avionics
avionics.power()
Expand Down Expand Up @@ -350,7 +352,8 @@ def add_unknowns_and_residuals_to_segment(self, segment, initial_power_coefficie
n_res = n_props

# Assign initial segment conditions to segment if missing
append_initial_battery_conditions(segment)
battery = self.battery
append_initial_battery_conditions(segment,battery)

# Setup the residuals
segment.state.residuals.network = 0. * ones_row(n_res)
Expand All @@ -359,12 +362,15 @@ def add_unknowns_and_residuals_to_segment(self, segment, initial_power_coefficie
segment.state.unknowns.propeller_power_coefficient = initial_power_coefficient * ones_row(n_props)

# Setup the conditions
segment.state.conditions.propulsion.propeller_motor_torque = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_torque = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_rpm = 0. * ones_row(n_props)
segment.state.conditions.propulsion.disc_loading = 0. * ones_row(n_props)
segment.state.conditions.propulsion.power_loading = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_tip_mach = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_motor_efficiency = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_motor_torque = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_torque = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_thrust = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_rpm = 0. * ones_row(n_props)
segment.state.conditions.propulsion.disc_loading = 0. * ones_row(n_props)
segment.state.conditions.propulsion.power_loading = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_tip_mach = 0. * ones_row(n_props)
segment.state.conditions.propulsion.propeller_efficiency = 0. * ones_row(n_props)

# Ensure the mission knows how to pack and unpack the unknowns and residuals
segment.process.iterate.unknowns.network = self.unpack_unknowns
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,14 @@ def energy_calc(self,numerics,battery_discharge_flag= True):
Q_prior = battery.cell_charge_throughput
R_growth_factor = battery.R_growth_factor
E_growth_factor = battery.E_growth_factor
I = numerics.time.integrate
I = numerics.time.integrate
D = numerics.time.differentiate

if not battery_discharge_flag:
I_bat = -I_bat
# ---------------------------------------------------------------------------------
# Compute battery electrical properties
# ---------------------------------------------------------------------------------
n_parallel = battery.pack_config.parallel

# Update battery capacitance (energy) with aging factor
E_max = E_max*E_growth_factor
Expand All @@ -176,6 +176,21 @@ def energy_calc(self,numerics,battery_discharge_flag= True):
dT_dt = Q_heat_gen /(bat_mass*bat_Cp)
T_current = T_current[0] + np.dot(I,dT_dt)

# Possible Energy going into the battery:
energy_unmodified = np.dot(I,P)

# Available capacity
capacity_available = E_max - battery.current_energy[0]

# How much energy the battery could be overcharged by
delta = energy_unmodified -capacity_available
delta[delta<0.] = 0.

# Power that shouldn't go in
ddelta = np.dot(D,delta)

# Power actually going into the battery
P[P>0.] = P[P>0.] - ddelta[P>0.]
E_bat = np.dot(I,P)
E_bat = np.reshape(E_bat,np.shape(E_current)) #make sure it's consistent

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

# package imports
import numpy as np
from scipy.integrate import cumtrapz

## @ingroup Components-Energy-Storages-Batteries-Constant_Mass
class Lithium_Ion_LiFePO4_18650(Lithium_Ion):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import numpy as np
import os
from scipy.integrate import cumtrapz , odeint
from scipy.integrate import cumtrapz
from scipy.interpolate import RegularGridInterpolator

## @ingroup Components-Energy-Storages-Batteries-Constant_Mass
Expand Down Expand Up @@ -155,11 +155,11 @@ def energy_calc(self,numerics,battery_discharge_flag = True ):
T_current = battery.pack_temperature
T_cell = battery.cell_temperature
E_max = battery.max_energy
R_growth_factor = battery.R_growth_factor
E_current = battery.current_energy
Q_prior = battery.cell_charge_throughput
battery_data = battery.discharge_performance_map
I = numerics.time.integrate
D = numerics.time.differentiate

# ---------------------------------------------------------------------------------
# Compute battery electrical properties
Expand Down Expand Up @@ -228,12 +228,31 @@ def energy_calc(self,numerics,battery_discharge_flag = True ):
# Compute updates state of battery
# ---------------------------------------------------------------------------------

# Determine actual power going into the battery accounting for resistance losses
E_bat = np.dot(I,P)
# Possible Energy going into the battery:
energy_unmodified = np.dot(I,P)

# Available capacity
capacity_available = E_max - battery.current_energy[0]

# How much energy the battery could be overcharged by
delta = energy_unmodified -capacity_available
delta[delta<0.] = 0.

# Power that shouldn't go in
ddelta = np.dot(D,delta)

# Power actually going into the battery
P[P>0.] = P[P>0.] - ddelta[P>0.]
E_bat = np.dot(I,P)
E_bat = np.reshape(E_bat,np.shape(E_current)) #make sure it's consistent

# Add this to the current state
if np.isnan(E_bat).any():
E_bat=np.ones_like(E_bat)*np.max(E_bat)
if np.isnan(E_bat.any()): #all nans; handle this instance
E_bat=np.zeros_like(E_bat)

# Determine current energy state of battery (from all previous segments)
E_current = E_bat + E_current[0]
E_current[E_current>E_max] = E_max

# Determine new State of Charge
SOC_new = np.divide(E_current, E_max)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# Methods
# ----------------------------------------------------------------------
## @ingroup Methods-Power-Battery
def append_initial_battery_conditions(segment):
def append_initial_battery_conditions(segment,battery):
""" Packs the initial battery conditions
Assumptions:
Expand Down Expand Up @@ -90,11 +90,21 @@ def append_initial_battery_conditions(segment):
pack_temperature = segment.battery_pack_temperature
propulsion.battery_pack_temperature[:,0] = pack_temperature
propulsion.battery_cell_temperature[:,0] = pack_temperature


if 'battery_max_aged_energy' in segment:
battery_max_aged_energy = segment.battery_max_aged_energy
else:
battery_max_aged_energy = battery.max_energy


propulsion.battery_max_aged_energy = battery_max_aged_energy



if 'battery_energy' in segment:

initial_segment_energy = segment.battery_energy
battery_max_aged_energy = segment.battery_energy
initial_mission_energy = segment.battery_energy

if 'battery_cycle_day' not in segment:
Expand All @@ -120,7 +130,7 @@ def append_initial_battery_conditions(segment):
# Pack into conditions
propulsion.battery_max_initial_energy = initial_mission_energy
propulsion.battery_energy[:,0] = initial_segment_energy
propulsion.battery_max_aged_energy = battery_max_aged_energy

propulsion.battery_cycle_day = cycle_day
propulsion.battery_cell_charge_throughput[:,0] = cell_charge_throughput
propulsion.battery_resistance_growth_factor = resistance_growth_factor
Expand Down

0 comments on commit 5bc7427

Please sign in to comment.