Skip to content

Commit

Permalink
Merge branch 'develop' into feature-versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
planes committed Nov 6, 2021
2 parents f2e446c + 5bc7427 commit 1a76904
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 54 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
28 changes: 13 additions & 15 deletions trunk/SUAVE/Input_Output/OpenVSP/vsp_wing.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,20 +135,20 @@ def read_vsp_wing(wing_id, units_type='SI',write_airfoil_file=True):
single_seg = True
else:
single_seg = False

segment_num = vsp.GetNumXSec(xsec_surf_id) # Get number of wing segments (is one more than the VSP GUI shows).
x_sec = vsp.GetXSec(xsec_surf_id, 0)
chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord')

total_chord = vsp.GetParmVal(chord_parm)

segment_num = vsp.GetNumXSec(xsec_surf_id) # Get number of segments

span_sum = 0. # Non-projected.
proj_span_sum = 0. # Projected.
segment_spans = [None] * (segment_num) # Non-projected.
segment_dihedral = [None] * (segment_num)
segment_sweeps_quarter_chord = [None] * (segment_num)
start = 0
root_chord = total_chord * units_factor

# Necessary wing segment definitions start at XSec_1 (XSec_0 exists mainly to hold the root airfoil)
xsec_surf_id = vsp.GetXSecSurf(wing_id, 0)
x_sec = vsp.GetXSec(xsec_surf_id, 1)
chord_parm = vsp.GetXSecParm(x_sec,'Root_Chord')
root_chord = vsp.GetParmVal(chord_parm) * units_factor

# -------------
# Wing segments
Expand All @@ -157,12 +157,10 @@ def read_vsp_wing(wing_id, units_type='SI',write_airfoil_file=True):
if single_seg == False:

# Convert VSP XSecs to SUAVE segments. (Wing segments are defined by outboard sections in VSP, but inboard sections in SUAVE.)
for i in range(start, segment_num+1):
for i in range(1, segment_num+1):
# XSec airfoil
if start!=0:
jj = i-1 # Airfoil index i-1 because VSP airfoils and sections are one index off relative to SUAVE.
else:
jj= i*1
jj = i-1 # Airfoil index i-1 because VSP airfoils and sections are one index off relative to SUAVE.

segment = SUAVE.Components.Wings.Segment()
segment.tag = 'Section_' + str(i)
thick_cord = vsp.GetParmVal(wing_id, 'ThickChord', 'XSecCurve_' + str(jj))
Expand All @@ -175,7 +173,7 @@ def read_vsp_wing(wing_id, units_type='SI',write_airfoil_file=True):
segment.percent_span_location = proj_span_sum / (total_proj_span/(1+wing.symmetric))
segment.twist = vsp.GetParmVal(wing_id, 'Twist', 'XSec_' + str(jj)) * Units.deg

if i==start:
if i==1:
wing.thickness_to_chord = thick_cord

if i < segment_num: # This excludes the tip xsec, but we need a segment in SUAVE to store airfoil.
Expand Down Expand Up @@ -243,7 +241,7 @@ def read_vsp_wing(wing_id, units_type='SI',write_airfoil_file=True):
span_sum_alt = 0.
sweeps_sum = 0.

for ii in range(start, segment_num):
for ii in range(1, segment_num):
span_sum_alt += segment_spans[ii]
proj_span_sum_alt += segment_spans[ii] * np.cos(segment_dihedral[ii]) # Use projected span to find total wing dihedral.
sweeps_sum += segment_spans[ii] * np.tan(segment_sweeps_quarter_chord[ii])
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 1a76904

Please sign in to comment.