F‑16 Fighting Falcon — Longitudinal Dynamics¶
The General Dynamics F‑16 Fighting Falcon is an American multirole lightweight 4th‑generation fighter. The library provides the longitudinal flight channel as a linear state‑space model together with a Gymnasium environment for training control agents.
-
Quick start
Run the environment or the model in just a few lines of code.
-
Model API
Python class documentation for the F‑16 longitudinal dynamics.
-
Gymnasium environment
Ready‑to‑use environment for training control agents.
-
Theory
State equations and data sources for the model.
Performance specs (reference)¶
| Parameter | Value |
|---|---|
| Variant | F‑16A Block 10 |
| Wingspan, m | 9.45 |
| Aircraft length (with pitot boom), m | 15.03 |
| Aircraft height, m | 5.09 |
| Wing area, m² | 27.87 |
| Sweep angle, ° | 40.0 |
| Normal takeoff weight, kg | 11467 |
Control object structure¶
The model is defined in the state space and describes the evolution of longitudinal variables when the stabilator deflection is used as the control input.
where the state vector and control input are defined as:
The typical matrix structure for the longitudinal channel is:
In this implementation the parameters come from the source listed below, are reduced to the selected variables, and the system is then discretized with the step dt.
- u: longitudinal velocity, m/s
- α: angle of attack, rad (API methods provide degree conversion)
- q: pitch rate, rad/s
- θ: pitch angle, rad
- η: stabilator deflection control input, rad
- x_u, x_α, x_q, x_θ: longitudinal force derivatives
- z_u, z_α, z_q, z_θ: normal force derivatives (row Z in the chosen axes)
- m_u, m_α, m_q, m_θ: pitch moment derivatives
Units
Inside the models, angles and angular rates are represented in radians. Methods that return state/control histories can convert values to degrees.
Mathematical model¶
Because the controlled plant has no internal disturbance processes, the system output \(y\) is not used in the simulation (\(C\) is diagonal, \(D\) is a zero matrix).
Derivatives (numerical values)¶
- Matrix A (derivatives):
| Coefficient | Value |
|---|---|
| x_u | -0.1656 |
| x_α | -10.7137 |
| x_q | -7.2815 |
| x_θ | -32.1740 |
| z_u | -0.0018 |
| z_α | -0.0981 |
| z_q | 0.9276 |
| z_θ | 0 |
| m_u | 0 |
| m_α | -0.6252 |
| m_q | -0.4673 |
| m_θ | 0 |
- Input η (column B):
| Coefficient | Value |
|---|---|
| x_η | -4.0478 |
| z_η | -0.0253 |
| m_η | -0.8992 |
Coefficient glossary¶
- x_u, x_α, x_q, x_θ — partial derivatives of longitudinal force \(X\) with respect to \(u, \alpha, q, \theta\)
- z_u, z_α, z_q, z_θ — partial derivatives of normal force \(Z\) with respect to \(u, \alpha, q, \theta\)
- m_u, m_α, m_q, m_θ — partial derivatives of pitch moment \(M\) with respect to \(u, \alpha, q, \theta\)
- x_η, z_η, m_η — partial derivatives with respect to the control input \(\eta\) (stabilator deflection)
where
- \(u\) — aircraft longitudinal velocity [m/s]
- \(\alpha\) — angle of attack [rad]
- \(q\) — pitch rate [rad/s]
- \(\theta\) — pitch angle [rad]
- \(\eta\) — stabilator deflection [rad]
Actuator limits
The model uses the following default control limits:
- Maximum magnitude: \(\pm 25^\circ\)
- Maximum rate: \(60^\circ/\text{s}\)
Internal computations use radians; the limits are converted accordingly.
Data source¶
- Albert Farré Gabernet, "Controllers for Systems with Bounded Actuators: Modeling and control of an F‑16 aircraft", University of California, Irvine. Link
Quick start¶
import gymnasium as gym
import numpy as np
from tensoraerospace.envs import LinearLongitudinalF16
from tensoraerospace.utils import generate_time_period
from tensoraerospace.signals.standard import unit_step
dt = 0.01
tp = generate_time_period(tn=20, dt=dt)
number_time_steps = len(tp)
reference_signal = unit_step(degree=5, tp=tp, time_step=10, output_rad=True).reshape(1, -1)
env = gym.make(
'LinearLongitudinalF16-v0',
number_time_steps=number_time_steps,
initial_state=[[0],[0]], # alpha, q
reference_signal=reference_signal,
)
state, info = env.reset()
for _ in range(200):
action = np.array([[0.1]]) # rad
state, reward, terminated, truncated, info = env.step(action)
if terminated or truncated:
break
import numpy as np
from tensoraerospace.aerospacemodel.f16.linear.longitudinal.model import LongitudinalF16
dt = 0.01
number_time_steps = 200
# Order of the model internal states: [theta, alpha, q, ele]
x0 = np.array([0.0, 0.0, 0.0, 0.0])
model = LongitudinalF16(
x0=x0,
number_time_steps=number_time_steps,
selected_state_output=["alpha", "q"],
dt=dt,
)
for t in range(number_time_steps - 1):
u = np.array([[0.1]]) # stabilator deflection (rad)
state_next = model.run_step(u)
Python API¶
LongitudinalF16(x0, number_time_steps, selected_state_output=None, t0=0, dt=0.01)
¶
Bases: ModelBase
Linearized longitudinal F-16 dynamics in state space.
The model describes the longitudinal channel of the aircraft with input via
stabilizer deflection and outputs via angles/velocities. State matrices are
loaded from prepared MATLAB files and reduced to selected variables, then the
system is discretized with step dt.
States (internal-model order): theta: pitch [rad] alpha: angle of attack [rad] q: pitch angular velocity [rad/s] ele: elevator position [rad]
Control
ele: stabilizer deflection [rad]
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x0
|
ndarray | list[float]
|
Initial model state in internal-model order (see list above). |
required |
number_time_steps
|
int
|
Number of simulation steps. |
required |
selected_state_output
|
list[str] | None
|
Names of states that are returned
externally (reduced state vector). If |
None
|
t0
|
float
|
Initial time, sec. |
0
|
dt
|
float
|
Discretization step, sec. |
0.01
|
Attributes:
| Name | Type | Description |
|---|---|---|
selected_states |
list[str]
|
List of internal-model states. |
selected_output |
list[str]
|
List of outputs. |
selected_input |
list[str]
|
List of control inputs. |
input_magnitude_limits |
list[float]
|
Control magnitude limits. |
input_rate_limits |
list[float]
|
Control rate limits. |
A, |
B, C, D (np.ndarray | None
|
Continuous matrices of original system. |
filt_A, |
filt_B, filt_C, filt_D (np.ndarray | None
|
Filtered and discretized matrices of reduced system. |
store_states, |
store_input, store_outputs (np.ndarray
|
History of states, inputs and outputs over simulation horizon. |
Notes
- Matrices are loaded from the
../datadirectory relative to this file. - Discretization is performed using
scipy.signal.cont2discrete. - Units: angles and angular rates inside the model are in radians.
import_linear_system()
¶
Load linearized state-space matrices from MATLAB files.
simplify_system()
¶
Reduce the system to selected states/outputs and form filtered matrices.
create_dictionary(file_name)
¶
Create a dictionary that maps quantity names to indices (state/input/output).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_name
|
str
|
Key file name ( |
required |
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
dict[str, int]: Mapping from quantity name to row/column index. |
initialise_system(x0, number_time_steps)
¶
Initialize the system, discretize it, and allocate history buffers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x0
|
ndarray
|
Initial state. |
required |
number_time_steps
|
int
|
Simulation horizon. |
required |
run_step(ut_0)
¶
Perform one evolution step subject to control constraints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ut_0
|
ndarray
|
Control vector at the current step (rad). |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Next-step state |
update_system_attributes()
¶
Update the current state and the internal model timer.
get_state(state_name, to_deg=False, to_rad=False)
¶
Get the state history array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state_name
|
str
|
State name. |
required |
to_deg
|
bool
|
Convert to degrees. |
False
|
to_rad
|
bool
|
Convert to radians. |
False
|
Returns:
| Type | Description |
|---|---|
ndarray
|
History array of the selected state. |
Example:
state_hist = model.get_state('alpha', to_deg=True)
get_control(control_name, to_deg=False, to_rad=False)
¶
Get the control signal history array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
control_name
|
str
|
Name of the control signal. |
required |
to_deg
|
bool
|
Convert to degrees. |
False
|
Returns:
| Type | Description |
|---|---|
ndarray
|
History array of the selected control signal. |
Example:
state_hist = model.get_control('stab', to_deg=True)
LinearLongitudinalF16(initial_state, reference_signal, number_time_steps, tracking_states=None, state_space=None, control_space=None, output_space=None, reward_func=None, use_reward=True)
¶
Bases: Env
Simulation of LongitudinalF16 control object in OpenAI Gym environment for training AI agents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_state
|
ndarray
|
Initial state. |
required |
reference_signal
|
ndarray
|
Reference signal. |
required |
number_time_steps
|
int
|
Number of simulation steps. |
required |
tracking_states
|
list[str] | None
|
Tracked states. |
None
|
state_space
|
list[str] | None
|
State space. |
None
|
control_space
|
list[str] | None
|
Control space. |
None
|
output_space
|
list[str] | None
|
Full output space (including noise). |
None
|
reward_func
|
Callable[[ndarray, ndarray, int], ndarray | float] | None
|
Reward function (WIP status). |
None
|
Initialize LinearLongitudinalF16 environment.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
initial_state
|
ndarray
|
Initial state. |
required |
reference_signal
|
ndarray
|
Reference signal. |
required |
number_time_steps
|
int
|
Number of simulation steps. |
required |
tracking_states
|
list
|
Tracked states. Defaults to ["alpha", "q"]. |
None
|
state_space
|
list
|
State space. Defaults to ["alpha", "q"]. |
None
|
control_space
|
list
|
Control space. Defaults to ["ele"]. |
None
|
output_space
|
list
|
Full output space. Defaults to ["alpha", "q"]. |
None
|
reward_func
|
callable
|
Reward function. Defaults to None. |
None
|
use_reward
|
bool
|
Whether to use reward. Defaults to True. |
True
|
get_init_args()
¶
Get initialization arguments as a dictionary.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict[str, object]
|
Dictionary of initialization arguments. |
step(action)
¶
Execute one simulation step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action
|
ndarray
|
Control signal array for selected actuators. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
tuple[ndarray, float, bool, bool, dict[str, float]]
|
Tuple containing: - next_state (np.ndarray): Next state of the control object. - reward (np.ndarray): Evaluation of control algorithm actions. - done (bool): Simulation status, whether completed or not. - truncated (bool): Whether episode was truncated. - info (dict): Additional information (not used). |
reset(seed=None, options=None)
¶
Reset simulation environment to initial conditions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int
|
Random seed. Defaults to None. |
None
|
options
|
dict
|
Reset options. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
tuple[ndarray, dict[str, float]]
|
Tuple containing: - observation (np.ndarray): Initial observation. - info (dict): Additional information. |
close()
¶
Release resources (no-op placeholder).
default_reward(state, ref_signal, ts)
staticmethod
¶
Reward function for RL environment in longitudinal aircraft control.
Supports variable-length state vectors. The last two elements of the
flattened state are treated as [tracked_angle, angular_rate] so the
reward works for both 2-state [alpha, q] and 3-state
[theta, alpha, q] configurations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
ndarray
|
Current aircraft state (at least 2 elements). |
required |
ref_signal
|
ndarray
|
Target angle trajectory, shape |
required |
ts
|
int
|
Current time step index. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
np.ndarray: Reward value for this step. |
