Source code for RCAIDE.Library.Mission.Common.Pre_Process.set_residuals_and_unknowns
# RCAIDE/Library/Missions/Common/Pre_Process/set_residuals_and_unknowns.py
#
#
# Created: Jul 2023, M. Clarke
# ----------------------------------------------------------------------------------------------------------------------
# IMPORT
# ----------------------------------------------------------------------------------------------------------------------
import RCAIDE
from RCAIDE.Framework.Core import Units
import numpy as np
# ----------------------------------------------------------------------------------------------------------------------
# set_residuals_and_unknowns
# ----------------------------------------------------------------------------------------------------------------------
[docs]
def set_residuals_and_unknowns(mission):
"""
Sets up flight dynamics residuals and control variables for mission segments
Parameters
----------
mission : Mission
The mission containing segments to be analyzed
- state.ones_row : function
Creates array of ones
- assigned_control_variables : Data
Control variable configurations
- flight_dynamics : Data
Force/moment flags
- state.residuals : Data
Storage for residuals
- state.unknowns : Data
Storage for unknowns
Returns
-------
None
Updates mission segment states directly
Notes
-----
This function configures the flight dynamics problem for each segment by
setting up force/moment residuals and initializing control variables.
It handles a comprehensive set of flight controls and dynamics states.
The function processes:
1. Force and moment residuals (degrees of freedom)
2. Control variable initialization including:
- Body angles
- Bank angles
- Wind angles
- Throttle settings
- Velocity and acceleration
- Time parameters
- Control surface deflections
* Elevator
* Rudder
* Flaps
* Slats
* Ailerons
- Thrust vectoring
**Control Variable Initialization**
For each control:
1. Check if active
2. Use provided initial values if available
3. Apply default values if needed
4. Track number of controls
**Major Assumptions**
* Valid control configurations
* Proper degrees of freedom setup
* Compatible control assignments
* Valid initial guess values
* Units in standard format
See Also
--------
RCAIDE.Framework.Mission.Segments
"""
for segment in mission.segments:
ones_row = segment.state.ones_row
ones_row_m1 = segment.state.ones_row_m1
ctrls = segment.assigned_control_variables
dynamics = segment.flight_dynamics
if type(segment) == RCAIDE.Framework.Mission.Segments.Climb.Constant_Dynamic_Pressure_Constant_Angle or \
type(segment) == RCAIDE.Framework.Mission.Segments.Climb.Constant_Mach_Constant_Angle:
segment.state.residuals.altitude = ones_row(1) * 0.0
segment.state.number_of_residuals += 1
# assign force and moment residuals i.e. degrees of freedom
if dynamics.final_velocity_error == True:
segment.state.residuals.final_velocity_error = 0.0
segment.state.number_of_residuals += 1
if dynamics.force_x == True:
if type(segment) == RCAIDE.Framework.Mission.Segments.Ground.Takeoff or \
type(segment) == RCAIDE.Framework.Mission.Segments.Ground.Landing:
pass
else:
segment.state.residuals.force_x = ones_row(1) *0
segment.state.number_of_residuals += 1
if dynamics.force_y == True:
segment.state.residuals.force_y = ones_row(1) *0
segment.state.number_of_residuals += 1
if dynamics.force_z == True:
segment.state.residuals.force_z = ones_row(1) *0
segment.state.number_of_residuals += 1
if dynamics.moment_x == True:
segment.state.residuals.moment_x = ones_row(1) *0
segment.state.number_of_residuals += 1
if dynamics.moment_y == True:
segment.state.residuals.moment_y = ones_row(1) *0
segment.state.number_of_residuals += 1
if dynamics.moment_z == True:
segment.state.residuals.moment_z = ones_row(1) *0
segment.state.number_of_residuals += 1
# Body Angle
if ctrls.pitch_angle.active:
segment.state.number_of_unknowns += 1
if ctrls.pitch_angle.initial_guess_values != None:
segment.state.unknowns.pitch_angle = ones_row(1) * ctrls.pitch_angle.initial_guess_values[0][0]
else:
segment.state.unknowns.pitch_angle = ones_row(1) * 3.0 * Units.degrees
if ctrls.pitch_angle.bounds != None:
segment.state.numerics.solver.lower_bounds.pitch_angle = ctrls.pitch_angle.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.pitch_angle = ctrls.pitch_angle.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.pitch_angle = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.pitch_angle = np.inf * ones_row(1)
# Bank Angle
if ctrls.bank_angle.active:
segment.state.number_of_unknowns += 1
if ctrls.bank_angle.initial_guess_values != None:
segment.state.unknowns.bank_angle = ones_row(1) * ctrls.bank_angle.initial_guess_values[0][0]
else:
segment.state.unknowns.bank_angle = ones_row(1) * 0.0 * Units.degrees
if ctrls.bank_angle.bounds != None:
segment.state.numerics.solver.lower_bounds.bank_angle = ctrls.bank_angle.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.bank_angle = ctrls.bank_angle.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.bank_angle = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.bank_angle = np.inf * ones_row(1)
# Wing Angle
if ctrls.angle_of_attack.active:
segment.state.number_of_unknowns += 1
if ctrls.angle_of_attack.initial_guess_values != None:
segment.state.unknowns.angle_of_attack = ones_row(1) * ctrls.angle_of_attack.initial_guess_values[0][0]
else:
segment.state.unknowns.angle_of_attack = ones_row(1) * 1.0 * Units.degrees
if ctrls.angle_of_attack.bounds != None:
segment.state.numerics.solver.lower_bounds.angle_of_attack = ctrls.angle_of_attack.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.angle_of_attack = ctrls.angle_of_attack.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.angle_of_attack = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.angle_of_attack = np.inf * ones_row(1)
# Sideslip Angle
if ctrls.sideslip_angle.active:
segment.state.number_of_unknowns += 1
if ctrls.sideslip_angle.initial_guess_values != None:
segment.state.unknowns.sideslip_angle = ones_row(1) * ctrls.sideslip_angle.initial_guess_values[0][0]
else:
segment.state.unknowns.sideslip_angle = ones_row(1) * 0.0 * Units.degrees
if ctrls.sideslip_angle.bounds != None:
segment.state.numerics.solver.lower_bounds.sideslip_angle = ctrls.sideslip_angle.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.sideslip_angle = ctrls.sideslip_angle.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.sideslip_angle = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.sideslip_angle = np.inf * ones_row(1)
# Throttle
if ctrls.throttle.active:
for i in range(len(ctrls.throttle.assigned_propulsors)):
segment.state.number_of_unknowns += 1
if ctrls.throttle.initial_guess_values != None:
segment.state.unknowns["throttle_" + str(i)] = ones_row(1) * ctrls.throttle.initial_guess_values[i][0]
else:
segment.state.unknowns["throttle_" + str(i)] = ones_row(1) * 0.5
if ctrls.throttle.bounds != None:
segment.state.numerics.solver.lower_bounds["throttle_" + str(i)] = ctrls.throttle.bounds[i][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds["throttle_" + str(i)] = ctrls.throttle.bounds[i][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds["throttle_" + str(i)] = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds["throttle_" + str(i)] = np.inf * ones_row(1)
# Thrust Vector
if ctrls.thrust_vector_angle.active:
for i in range(len(ctrls.thrust_vector_angle.assigned_propulsors)):
segment.state.number_of_unknowns += 1
if ctrls.thrust_vector_angle.initial_guess_values != None:
segment.state.unknowns["thrust_vector_angle_" + str(i)] = ones_row(1) * ctrls.thrust_vector_angle.initial_guess_values[i][0]
else:
segment.state.unknowns["thrust_vector_angle_" + str(i)] = ones_row(1) * 0.5
if ctrls.thrust_vector_angle.bounds != None:
segment.state.numerics.solver.lower_bounds["thrust_vector_angle_" + str(i)] = ctrls.thrust_vector_angle.bounds[i][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds["thrust_vector_angle_" + str(i)] = ctrls.thrust_vector_angle.bounds[i][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds["thrust_vector_angle_" + str(i)] = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds["thrust_vector_angle_" + str(i)] = np.inf * ones_row(1)
# Blade Pitch Command
if ctrls.blade_pitch_command.active:
for i in range(len(ctrls.blade_pitch_command.assigned_rotors)):
segment.state.number_of_unknowns += 1
if ctrls.blade_pitch_command.initial_guess_values != None:
segment.state.unknowns["blade_pitch_command_" + str(i)] = ones_row(1) * ctrls.blade_pitch_command.initial_guess_values[i][0]
else:
segment.state.unknowns["blade_pitch_command_" + str(i)] = ones_row(1) * 0.5
if ctrls.blade_pitch_command.bounds != None:
segment.state.numerics.solver.lower_bounds["blade_pitch_command_" + str(i)] = ctrls.blade_pitch_command.bounds[i][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds["blade_pitch_command_" + str(i)] = ctrls.blade_pitch_command.bounds[i][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds["blade_pitch_command_" + str(i)] = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds["blade_pitch_command_" + str(i)] = np.inf * ones_row(1)
# Velocity
if ctrls.velocity.active:
segment.state.number_of_unknowns += 1
if ctrls.velocity.initial_guess_values != None:
segment.state.unknowns.velocity = ones_row(1) * ctrls.velocity.initial_guess_values[0][0]
else:
segment.state.unknowns.velocity = ones_row(1) * 100
if ctrls.velocity.bounds != None:
segment.state.numerics.solver.lower_bounds.velocity = ctrls.velocity.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.velocity = ctrls.velocity.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.velocity = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.velocity = np.inf * ones_row(1)
# Ground Velocity
if ctrls.ground_velocity.active:
segment.state.number_of_unknowns += 1
if ctrls.ground_velocity.initial_guess_values != None:
segment.state.unknowns.ground_velocity = ones_row(1) * ctrls.ground_velocity.initial_guess_values[0][0]
else:
segment.state.unknowns.ground_velocity = ones_row(1) * 100
if ctrls.ground_velocity.bounds != None:
segment.state.numerics.solver.lower_bounds.ground_velocity = ctrls.ground_velocity.bounds[0][0] * ones_row_m1(1)
segment.state.numerics.solver.upper_bounds.ground_velocity = ctrls.ground_velocity.bounds[0][1] * ones_row_m1(1)
else:
segment.state.numerics.solver.lower_bounds.ground_velocity = -np.inf * ones_row_m1(1)
segment.state.numerics.solver.upper_bounds.ground_velocity = np.inf * ones_row_m1(1)
# Altitude
if ctrls.altitude.active:
segment.state.number_of_unknowns += 1
if ctrls.altitude.initial_guess_values != None:
segment.state.unknowns.altitude = ctrls.altitude.initial_guess_values[0][0]
else:
segment.state.unknowns.altitude = ones_row(1) * 0.0
if ctrls.altitude.bounds != None:
segment.state.numerics.solver.lower_bounds.altitude = ctrls.altitude.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.altitude = ctrls.altitude.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.altitude = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.altitude = np.inf * ones_row(1)
# Acceleration
if ctrls.acceleration.active:
segment.state.number_of_unknowns += 1
if ctrls.acceleration.initial_guess_values != None:
segment.state.unknowns.acceleration = ones_row(1) * ctrls.acceleration.initial_guess_values[0][0]
else:
segment.state.unknowns.acceleration = ones_row(1) * 1.
if ctrls.acceleration.bounds != None:
segment.state.numerics.solver.lower_bounds.acceleration = ctrls.acceleration.bounds[0][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds.acceleration = ctrls.acceleration.bounds[0][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds.acceleration = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds.acceleration = np.inf * ones_row(1)
# Time
if ctrls.elapsed_time.active:
segment.state.number_of_unknowns += 1
if ctrls.elapsed_time.initial_guess_values != None:
segment.state.unknowns.elapsed_time = ctrls.elapsed_time.initial_guess_values[0][0]
else:
segment.state.unknowns.elapsed_time = 30
if ctrls.elapsed_time.bounds != None:
segment.state.numerics.solver.lower_bounds.elapsed_time = ctrls.elapsed_time.bounds[0][0]
segment.state.numerics.solver.upper_bounds.elapsed_time = ctrls.elapsed_time.bounds[0][1]
else:
segment.state.numerics.solver.lower_bounds.elapsed_time = -np.inf
segment.state.numerics.solver.upper_bounds.elapsed_time = np.inf
# Elevator
if ctrls.elevator_deflection.active:
segment.state.number_of_unknowns += 1
if ctrls.elevator_deflection.initial_guess_values!= None:
segment.state.unknowns["elevator"] = ones_row(1) * ctrls.elevator_deflection.initial_guess_values[0][0]
else:
segment.state.unknowns["elevator"] = ones_row(1) * 0.0 * Units.degrees
if ctrls.elevator_deflection.bounds != None:
segment.state.numerics.solver.lower_bounds["elevator"] = ctrls.elevator_deflection.bounds[i][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds["elevator"] = ctrls.elevator_deflection.bounds[i][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds["elevator"] = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds["elevator"] = np.inf * ones_row(1)
# Rudder
if ctrls.rudder_deflection.active:
segment.state.number_of_unknowns += 1
if ctrls.rudder_deflection.initial_guess_values != None:
segment.state.unknowns["rudder"] = ones_row(1) * ctrls.rudder_deflection.initial_guess_values[0][0]
else:
segment.state.unknowns["rudder"] = ones_row(1) * 0.0 * Units.degrees
if ctrls.rudder_deflection.bounds != None:
segment.state.numerics.solver.lower_bounds["rudder"] = ctrls.rudder_deflection.bounds[i][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds["rudder"] = ctrls.rudder_deflection.bounds[i][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds["rudder"] = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds["rudder"] = np.inf * ones_row(1)
# Aileron
if ctrls.aileron_deflection.active:
segment.state.number_of_unknowns += 1
if ctrls.aileron_deflection.initial_guess_values != None:
segment.state.unknowns["aileron" ] = ones_row(1) * ctrls.aileron_deflection.initial_guess_values[0][0]
else:
segment.state.unknowns["aileron" ] = ones_row(1) * 0.0 * Units.degrees
if ctrls.aileron_deflection.bounds != None:
segment.state.numerics.solver.lower_bounds["aileron"] = ctrls.aileron_deflection.bounds[i][0] * ones_row(1)
segment.state.numerics.solver.upper_bounds["aileron"] = ctrls.aileron_deflection.bounds[i][1] * ones_row(1)
else:
segment.state.numerics.solver.lower_bounds["aileron"] = -np.inf * ones_row(1)
segment.state.numerics.solver.upper_bounds["aileron"] = np.inf * ones_row(1)
return