Skip to content
This repository was archived by the owner on Aug 13, 2020. It is now read-only.

Commit af8710e

Browse files
committed
Merge pull request #51 from AlexS12/trimmer
Steady-state trimmer Según lo hablado en la [reunión 3](https://github.com/AeroPython/PyFME/wiki/Reuni%C3%B3n-3) se hace el merge. * Las validaciones se han hecho sobre el modelo de avión actual. * Los casos de ejemplo se mejorarán con el trabajo en los issues #58 y #57 (@olrosales) * La inicialización se mejorará buscando algún método empírico simplificado (@JuanMatSa)
2 parents 76d7b55 + 2f0eba8 commit af8710e

File tree

10 files changed

+1053
-109
lines changed

10 files changed

+1053
-109
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ before_install:
2222
- source activate test-environment
2323

2424
install:
25-
- conda install numpy pytest
25+
- conda install numpy pytest scipy
2626
- pip install -e .
2727

2828
script:

environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
name: pyfme
22
dependencies:
33
- numpy >=1.7
4+
- scipy >=0.17.0

examples/example_001.py

Lines changed: 116 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,151 @@
11
# -*- coding: utf-8 -*-
22
"""
3-
Dummy example
4-
5-
@author: asaez
3+
Python Flight Mechanics Engine (PyFME).
4+
Copyright (c) AeroPython Development Team.
5+
Distributed under the terms of the MIT License.
6+
7+
Example with trimmed aircraft.
8+
The main purpose of this example is to check if the aircraft trimmed in a given
9+
state maintains the trimmed flight condition.
10+
Trimmed in stationary, horizontal, symmetric, wings level flight.
611
"""
712

813
import numpy as np
914
import matplotlib.pyplot as plt
1015

16+
from pyfme.aircrafts import cessna_310
1117
from pyfme.models.system import System
18+
from pyfme.utils.trimmer import steady_state_flight_trim
19+
from pyfme.utils.anemometry import calculate_alpha_beta_TAS
20+
from pyfme.environment.isa import atm
1221

1322

23+
if __name__ == '__main__':
1424

15-
def forces():
16-
return np.array([0, 0, -9.8*500])
17-
18-
19-
def moments():
20-
return np.array([0, 0, 0])
21-
25+
# Aircraft parameters.
26+
mass, inertia = cessna_310.mass_and_inertial_data()
2227

23-
if __name__ == '__main__':
28+
# Initial conditions.
29+
TAS_ = 312 * 0.3048 # m/s
30+
h = 8000 * 0.3048 # m
31+
psi_0 = 3 # rad
32+
x_0, y_0 = 0, 0 # m
2433

25-
# Case params
26-
mass = 500
27-
inertia = np.array([[1, 0, 0],
28-
[0, 1, 0],
29-
[0, 0, 1]])
34+
# Trimming.
35+
trim_results = steady_state_flight_trim(cessna_310, h, TAS_, gamma=0,
36+
turn_rate=0)
3037

31-
# initial conditions
32-
u, v, w = 0, 0, 0
33-
p, q, r = 0, 0, 0
38+
lin_vel, ang_vel, theta, phi, alpha_, beta_, control_vector = trim_results
3439

35-
theta, phi, psi = 0, 0, 0
36-
x, y, z = 0, 0, 5000
40+
# Time.
41+
t0 = 0 # s
42+
tf = 30 # s
43+
dt = 1e-2 # s
3744

38-
t0 = 0
39-
tf = 10
40-
dt = 1e-2
4145
time = np.arange(t0, tf, dt)
4246

47+
# Results initialization.
4348
results = np.zeros([time.size, 12])
4449

45-
velocities = np.empty([time.size, 6])
46-
results[0, 0:6] = u, v, w, p, q, r
47-
results[0, 6:9] = theta, phi, psi
48-
results[0, 9:12] = x, y, z
50+
results[0, 0:3] = lin_vel
51+
results[0, 3:6] = ang_vel
52+
results[0, 6:9] = theta, phi, psi_0
53+
results[0, 9:12] = x_0, y_0, h
54+
alpha = np.empty_like(time)
55+
alpha[0] = alpha_
56+
beta = np.empty_like(time)
57+
beta[0] = beta_
58+
TAS = np.empty_like(time)
59+
TAS[0] = TAS_
60+
61+
# Linear Momentum and Angular Momentum eqs.
62+
equations = System(integrator='dopri5',
63+
model='euler_flat_earth',
64+
jac=False)
65+
u, v, w = lin_vel
66+
p, q, r = ang_vel
67+
68+
equations.set_initial_values(u, v, w,
69+
p, q, r,
70+
theta, phi, psi_0,
71+
x_0, y_0, h)
72+
73+
_, _, rho, _ = atm(h)
74+
75+
# Define control vectors.
76+
d_e, d_a, d_r, d_t = control_vector
77+
78+
attitude = theta, phi, psi_0
79+
80+
# Rename function to make it shorter
81+
forces_and_moments = cessna_310.get_forces_and_moments
82+
for ii, t in enumerate(time[1:]):
4983

50-
# Linear Momentum and Angular Momentum eqs
51-
equations = System(integrator='dopri5', model='euler_flat_earth', jac=False)
52-
equations.set_initial_values(u, v, w, p, q, r, theta, phi, psi, x, y, z)
84+
forces, moments = forces_and_moments(TAS[ii], rho, alpha[ii], beta[ii],
85+
d_e, 0, d_a, d_r, d_t, attitude)
5386

87+
results[ii+1, :] = equations.propagate(mass, inertia, forces, moments,
88+
dt)
5489

55-
for ii, t in enumerate(time[1:]):
56-
results[ii+1, :] = equations.propagate(mass, inertia, forces(), moments(),
57-
dt=dt)
90+
lin_vel = results[ii+1, 0:3]
91+
ang_vel = results[ii+1, 3:6]
92+
attitude = results[ii+1, 6:9]
93+
position = results[ii+1, 9:12]
94+
95+
alpha[ii+1], beta[ii+1], TAS[ii+1] = calculate_alpha_beta_TAS(*lin_vel)
96+
97+
_, _, rho, _ = atm(position[2])
5898

5999
velocities = results[:, 0:6]
60100
attitude_angles = results[:, 6:9]
61101
position = results[:, 9:12]
62102

63-
# TODO: improve graphics: legend title....
103+
# PLOTS
104+
plt.close('all')
105+
plt.style.use('ggplot')
106+
64107
plt.figure('pos')
65-
plt.plot(time, position[:, 0])
66-
plt.plot(time, position[:, 1])
67-
plt.plot(time, position[:, 2])
108+
plt.plot(time, position[:, 0], label='x')
109+
plt.plot(time, position[:, 1], label='y')
110+
plt.plot(time, position[:, 2], label='z')
111+
plt.xlabel('time (s)')
112+
plt.ylabel('position (m)')
113+
plt.legend()
68114

69115
plt.figure('angles')
70-
plt.plot(time, attitude_angles[:, 0])
71-
plt.plot(time, attitude_angles[:, 1])
72-
plt.plot(time, attitude_angles[:, 2])
116+
plt.plot(time, attitude_angles[:, 0], label='theta')
117+
plt.plot(time, attitude_angles[:, 1], label='phi')
118+
plt.plot(time, attitude_angles[:, 2], label='psi')
119+
plt.xlabel('time (s)')
120+
plt.ylabel('attitude (rad)')
121+
plt.legend()
73122

74123
plt.figure('velocities')
75-
plt.plot(time, velocities[:, 0])
76-
plt.plot(time, velocities[:, 1])
77-
plt.plot(time, velocities[:, 2])
124+
plt.plot(time, velocities[:, 0], label='u')
125+
plt.plot(time, velocities[:, 1], label='v')
126+
plt.plot(time, velocities[:, 2], label='w')
127+
plt.plot(time, TAS, label='TAS')
128+
plt.xlabel('time (s)')
129+
plt.ylabel('velocity (m/s)')
130+
plt.legend()
78131

79132
plt.figure('ang velocities')
80-
plt.plot(time, velocities[:, 3])
81-
plt.plot(time, velocities[:, 4])
82-
plt.plot(time, velocities[:, 5])
133+
plt.plot(time, velocities[:, 3], label='p')
134+
plt.plot(time, velocities[:, 4], label='q')
135+
plt.plot(time, velocities[:, 5], label='r')
136+
plt.xlabel('time (s)')
137+
plt.ylabel('angular velocity (rad/s)')
138+
plt.legend()
139+
140+
plt.figure('aero angles')
141+
plt.plot(time, alpha, label='alpha')
142+
plt.plot(time, beta, label='beta')
143+
plt.xlabel('time (s)')
144+
plt.ylabel('angle (rad)')
145+
plt.legend()
146+
147+
plt.figure('2D Trajectory')
148+
plt.plot(position[:, 0], position[:, 1])
149+
plt.xlabel('X (m)')
150+
plt.ylabel('Y (m)')
151+
plt.legend()

examples/example_002.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Python Flight Mechanics Engine (PyFME).
4+
Copyright (c) AeroPython Development Team.
5+
Distributed under the terms of the MIT License.
6+
7+
Example with trimmed aircraft.
8+
The main purpose of this example is to check if the aircraft trimmed in a given
9+
state maintains the trimmed flight condition.
10+
Trimmed in stationary descent, symmetric, wings level flight.
11+
"""
12+
13+
import numpy as np
14+
import matplotlib.pyplot as plt
15+
16+
from pyfme.aircrafts import cessna_310
17+
from pyfme.models.system import System
18+
from pyfme.utils.trimmer import steady_state_flight_trim
19+
from pyfme.utils.anemometry import calculate_alpha_beta_TAS
20+
from pyfme.environment.isa import atm
21+
22+
23+
if __name__ == '__main__':
24+
25+
# Aircraft parameters.
26+
mass, inertia = cessna_310.mass_and_inertial_data()
27+
28+
# Initial conditions.
29+
TAS_ = 312 * 0.3048 # m/s
30+
h = 8000 * 0.3048 # m
31+
psi_0 = 3 # rad
32+
x_0, y_0 = 0, 0 # m
33+
34+
# Trimming.
35+
trim_results = steady_state_flight_trim(cessna_310, h, TAS_, gamma=0.20,
36+
turn_rate=0)
37+
38+
lin_vel, ang_vel, theta, phi, alpha_, beta_, control_vector = trim_results
39+
40+
# Time.
41+
t0 = 0 # s
42+
tf = 120 # s
43+
dt = 1e-2 # s
44+
45+
time = np.arange(t0, tf, dt)
46+
47+
# Results initialization.
48+
results = np.zeros([time.size, 12])
49+
50+
results[0, 0:3] = lin_vel
51+
results[0, 3:6] = ang_vel
52+
results[0, 6:9] = theta, phi, psi_0
53+
results[0, 9:12] = x_0, y_0, h
54+
alpha = np.empty_like(time)
55+
alpha[0] = alpha_
56+
beta = np.empty_like(time)
57+
beta[0] = beta_
58+
TAS = np.empty_like(time)
59+
TAS[0] = TAS_
60+
61+
# Linear Momentum and Angular Momentum eqs.
62+
equations = System(integrator='dopri5',
63+
model='euler_flat_earth',
64+
jac=False)
65+
u, v, w = lin_vel
66+
p, q, r = ang_vel
67+
68+
equations.set_initial_values(u, v, w,
69+
p, q, r,
70+
theta, phi, psi_0,
71+
x_0, y_0, h)
72+
73+
_, _, rho, _ = atm(h)
74+
75+
# Define control vectors.
76+
d_e, d_a, d_r, d_t = control_vector
77+
78+
attitude = theta, phi, psi_0
79+
80+
# Rename function to make it shorter
81+
forces_and_moments = cessna_310.get_forces_and_moments
82+
for ii, t in enumerate(time[1:]):
83+
84+
forces, moments = forces_and_moments(TAS[ii], rho, alpha[ii], beta[ii],
85+
d_e, 0, d_a, d_r, d_t, attitude)
86+
87+
results[ii+1, :] = equations.propagate(mass, inertia, forces, moments,
88+
dt)
89+
90+
lin_vel = results[ii+1, 0:3]
91+
ang_vel = results[ii+1, 3:6]
92+
attitude = results[ii+1, 6:9]
93+
position = results[ii+1, 9:12]
94+
95+
alpha[ii+1], beta[ii+1], TAS[ii+1] = calculate_alpha_beta_TAS(*lin_vel)
96+
97+
_, _, rho, _ = atm(position[2])
98+
99+
velocities = results[:, 0:6]
100+
attitude_angles = results[:, 6:9]
101+
position = results[:, 9:12]
102+
103+
# PLOTS
104+
plt.close('all')
105+
plt.style.use('ggplot')
106+
107+
plt.figure('pos')
108+
plt.plot(time, position[:, 0], label='x')
109+
plt.plot(time, position[:, 1], label='y')
110+
plt.plot(time, position[:, 2], label='z')
111+
plt.xlabel('time (s)')
112+
plt.ylabel('position (m)')
113+
plt.legend()
114+
115+
plt.figure('angles')
116+
plt.plot(time, attitude_angles[:, 0], label='theta')
117+
plt.plot(time, attitude_angles[:, 1], label='phi')
118+
plt.plot(time, attitude_angles[:, 2], label='psi')
119+
plt.xlabel('time (s)')
120+
plt.ylabel('attitude (rad)')
121+
plt.legend()
122+
123+
plt.figure('velocities')
124+
plt.plot(time, velocities[:, 0], label='u')
125+
plt.plot(time, velocities[:, 1], label='v')
126+
plt.plot(time, velocities[:, 2], label='w')
127+
plt.plot(time, TAS, label='TAS')
128+
plt.xlabel('time (s)')
129+
plt.ylabel('velocity (m/s)')
130+
plt.legend()
131+
132+
plt.figure('ang velocities')
133+
plt.plot(time, velocities[:, 3], label='p')
134+
plt.plot(time, velocities[:, 4], label='q')
135+
plt.plot(time, velocities[:, 5], label='r')
136+
plt.xlabel('time (s)')
137+
plt.ylabel('angular velocity (rad/s)')
138+
plt.legend()
139+
140+
plt.figure('aero angles')
141+
plt.plot(time, alpha, label='alpha')
142+
plt.plot(time, beta, label='beta')
143+
plt.xlabel('time (s)')
144+
plt.ylabel('angle (rad)')
145+
plt.legend()
146+
147+
plt.figure('2D Trajectory')
148+
plt.plot(position[:, 0], position[:, 1])
149+
plt.xlabel('X (m)')
150+
plt.ylabel('Y (m)')
151+
plt.legend()

0 commit comments

Comments
 (0)