Vulcan
Aerospace Engineering Utilities Built on Janus
Loading...
Searching...
No Matches
VonKarmanTurbulence.hpp
Go to the documentation of this file.
1// von Kármán Turbulence Model
2// Higher-order approximate forming filters (MIL-F-8785C / MIL-HDBK-1797)
3#pragma once
4
5#include <array>
6#include <cmath>
8
10
11// ============================================================================
12// Physical Constants
13// ============================================================================
14
16inline constexpr double SPECTRAL_CONSTANT = 1.339;
17
18// ============================================================================
19// Power Spectral Density Functions
20// ============================================================================
21
36template <typename Scalar>
37Scalar psd_longitudinal(const Scalar &omega, double sigma_u, double L_u) {
38 Scalar L_omega = SPECTRAL_CONSTANT * L_u * omega;
39 Scalar denom = Scalar(1) + L_omega * L_omega;
40 // (1 + x)^(5/6) = (1 + x)^(5/6)
41 return sigma_u * sigma_u * (2.0 * L_u / M_PI) /
42 janus::pow(denom, 5.0 / 6.0);
43}
44
57template <typename Scalar>
58Scalar psd_lateral(const Scalar &omega, double sigma, double L) {
59 Scalar L_omega = SPECTRAL_CONSTANT * L * omega;
60 Scalar L_omega_sq = L_omega * L_omega;
61 Scalar numer = Scalar(1) + Scalar(8.0 / 3.0) * L_omega_sq;
62 Scalar denom = Scalar(1) + L_omega_sq;
63 return sigma * sigma * (L / M_PI) * numer / janus::pow(denom, 11.0 / 6.0);
64}
65
66// ============================================================================
67// Forming Filter State (Higher Order)
68// ============================================================================
69
76template <typename Scalar> struct FilterState {
77 std::array<Scalar, 3> x_u;
78 std::array<Scalar, 4> x_v;
79 std::array<Scalar, 4> x_w;
80};
81
85template <typename Scalar> FilterState<Scalar> init_state() {
87 for (auto &s : state.x_u)
88 s = Scalar(0);
89 for (auto &s : state.x_v)
90 s = Scalar(0);
91 for (auto &s : state.x_w)
92 s = Scalar(0);
93 return state;
94}
95
96// ============================================================================
97// Filter Coefficients
98// ============================================================================
99
110 // Longitudinal (3rd order discrete system)
111 std::array<std::array<double, 3>, 3> A_u;
112 std::array<double, 3> B_u;
113 std::array<double, 3> C_u;
114 double D_u;
115
116 // Lateral (4th order discrete system)
117 std::array<std::array<double, 4>, 4> A_v;
118 std::array<double, 4> B_v;
119 std::array<double, 4> C_v;
120 double D_v;
121
122 // Vertical (4th order discrete system)
123 std::array<std::array<double, 4>, 4> A_w;
124 std::array<double, 4> B_w;
125 std::array<double, 4> C_w;
126 double D_w;
127};
128
143inline FilterCoeffs
145 double airspeed, double dt) {
146 FilterCoeffs coeffs;
147
148 // Longitudinal filter (3rd order approximation)
149 // Uses cascade of 3 first-order sections with varied time constants
150 // to approximate the 5/6 roll-off
151 double tau_u = SPECTRAL_CONSTANT * params.L_u / airspeed;
152
153 // Time constants for cascade approximation
154 double tau1 = tau_u * 1.0;
155 double tau2 = tau_u * 0.618; // Golden ratio provides good spread
156 double tau3 = tau_u * 0.382;
157
158 // Discretize using exponential mapping (exact for first-order)
159 double a1 = std::exp(-dt / tau1);
160 double a2 = std::exp(-dt / tau2);
161 double a3 = std::exp(-dt / tau3);
162
163 // State transition matrix (diagonal for cascade)
164 coeffs.A_u = {{{a1, 0, 0}, {0, a2, 0}, {0, 0, a3}}};
165
166 // Input vector
167 double k_u =
168 params.sigma_u * std::sqrt(2.0 * params.L_u / (M_PI * airspeed));
169 coeffs.B_u = {std::sqrt(1 - a1 * a1) * k_u, std::sqrt(1 - a2 * a2) * 0.5,
170 std::sqrt(1 - a3 * a3) * 0.25};
171
172 // Output vector (weighted sum)
173 coeffs.C_u = {0.6, 0.3, 0.1};
174 coeffs.D_u = 0.0;
175
176 // Lateral filter (4th order approximation)
177 double tau_v = SPECTRAL_CONSTANT * params.L_v / airspeed;
178 double tau_v1 = tau_v * 1.0;
179 double tau_v2 = tau_v * 0.75;
180 double tau_v3 = tau_v * 0.5;
181 double tau_v4 = tau_v * 0.25;
182
183 double av1 = std::exp(-dt / tau_v1);
184 double av2 = std::exp(-dt / tau_v2);
185 double av3 = std::exp(-dt / tau_v3);
186 double av4 = std::exp(-dt / tau_v4);
187
188 coeffs.A_v = {
189 {{av1, 0, 0, 0}, {0, av2, 0, 0}, {0, 0, av3, 0}, {0, 0, 0, av4}}};
190
191 double k_v = params.sigma_v * std::sqrt(params.L_v / (M_PI * airspeed));
192 coeffs.B_v = {std::sqrt(1 - av1 * av1) * k_v,
193 std::sqrt(1 - av2 * av2) * k_v * 0.707,
194 std::sqrt(1 - av3 * av3) * k_v * 0.5,
195 std::sqrt(1 - av4 * av4) * k_v * 0.25};
196
197 // Output weights for proper spectrum shaping
198 coeffs.C_v = {0.4, 0.35, 0.2, 0.05};
199 coeffs.D_v = 0.0;
200
201 // Vertical filter (same structure as lateral, different parameters)
202 double tau_w = SPECTRAL_CONSTANT * params.L_w / airspeed;
203 double tau_w1 = tau_w * 1.0;
204 double tau_w2 = tau_w * 0.75;
205 double tau_w3 = tau_w * 0.5;
206 double tau_w4 = tau_w * 0.25;
207
208 double aw1 = std::exp(-dt / tau_w1);
209 double aw2 = std::exp(-dt / tau_w2);
210 double aw3 = std::exp(-dt / tau_w3);
211 double aw4 = std::exp(-dt / tau_w4);
212
213 coeffs.A_w = {
214 {{aw1, 0, 0, 0}, {0, aw2, 0, 0}, {0, 0, aw3, 0}, {0, 0, 0, aw4}}};
215
216 double k_w = params.sigma_w * std::sqrt(params.L_w / (M_PI * airspeed));
217 coeffs.B_w = {std::sqrt(1 - aw1 * aw1) * k_w,
218 std::sqrt(1 - aw2 * aw2) * k_w * 0.707,
219 std::sqrt(1 - aw3 * aw3) * k_w * 0.5,
220 std::sqrt(1 - aw4 * aw4) * k_w * 0.25};
221
222 coeffs.C_w = {0.4, 0.35, 0.2, 0.05};
223 coeffs.D_w = 0.0;
224
225 return coeffs;
226}
227
228// ============================================================================
229// Filter Step Function
230// ============================================================================
231
246template <typename Scalar>
249 const Scalar &noise_u, const Scalar &noise_v, const Scalar &noise_w) {
250 // Longitudinal (3rd order cascade)
251 std::array<Scalar, 3> new_x_u;
252 Scalar u_g = Scalar(0);
253 for (size_t i = 0; i < 3; ++i) {
254 new_x_u[i] = coeffs.A_u[i][i] * state.x_u[i] + coeffs.B_u[i] * noise_u;
255 u_g = u_g + coeffs.C_u[i] * new_x_u[i];
256 }
257 state.x_u = new_x_u;
258
259 // Lateral (4th order cascade)
260 std::array<Scalar, 4> new_x_v;
261 Scalar v_g = Scalar(0);
262 for (size_t i = 0; i < 4; ++i) {
263 new_x_v[i] = coeffs.A_v[i][i] * state.x_v[i] + coeffs.B_v[i] * noise_v;
264 v_g = v_g + coeffs.C_v[i] * new_x_v[i];
265 }
266 state.x_v = new_x_v;
267
268 // Vertical (4th order cascade)
269 std::array<Scalar, 4> new_x_w;
270 Scalar w_g = Scalar(0);
271 for (size_t i = 0; i < 4; ++i) {
272 new_x_w[i] = coeffs.A_w[i][i] * state.x_w[i] + coeffs.B_w[i] * noise_w;
273 w_g = w_g + coeffs.C_w[i] * new_x_w[i];
274 }
275 state.x_w = new_x_w;
276
277 return wind::GustVelocity<Scalar>{.u_g = u_g, .v_g = v_g, .w_g = w_g};
278}
279
280// ============================================================================
281// Convenience Functions
282// ============================================================================
283
293inline FilterCoeffs mil_spec_coeffs(double altitude,
295 double airspeed, double dt) {
297 wind::mil_spec_params(altitude, severity);
298 return compute_filter_coeffs(params, airspeed, dt);
299}
300
301} // namespace vulcan::von_karman
Definition VonKarmanTurbulence.hpp:9
wind::GustVelocity< Scalar > step(FilterState< Scalar > &state, const FilterCoeffs &coeffs, const Scalar &noise_u, const Scalar &noise_v, const Scalar &noise_w)
Step the von Kármán forming filter.
Definition VonKarmanTurbulence.hpp:248
FilterCoeffs compute_filter_coeffs(const wind::TurbulenceParams< double > &params, double airspeed, double dt)
Compute von Kármán forming filter coefficients.
Definition VonKarmanTurbulence.hpp:144
Scalar psd_lateral(const Scalar &omega, double sigma, double L)
von Kármán lateral/vertical PSD
Definition VonKarmanTurbulence.hpp:58
FilterCoeffs mil_spec_coeffs(double altitude, wind::TurbulenceSeverity severity, double airspeed, double dt)
Compute all filter coefficients for MIL-spec conditions.
Definition VonKarmanTurbulence.hpp:293
Scalar psd_longitudinal(const Scalar &omega, double sigma_u, double L_u)
von Kármán longitudinal PSD
Definition VonKarmanTurbulence.hpp:37
FilterState< Scalar > init_state()
Initialize filter state to zero.
Definition VonKarmanTurbulence.hpp:85
constexpr double SPECTRAL_CONSTANT
von Kármán constant used in spectral formulation
Definition VonKarmanTurbulence.hpp:16
TurbulenceSeverity
Turbulence severity levels per MIL-HDBK-1797.
Definition WindTypes.hpp:85
TurbulenceParams< double > mil_spec_params(double altitude, TurbulenceSeverity severity)
Compute MIL-spec turbulence parameters for given conditions.
Definition WindTypes.hpp:125
von Kármán forming filter coefficients
Definition VonKarmanTurbulence.hpp:109
std::array< double, 4 > C_w
Definition VonKarmanTurbulence.hpp:125
std::array< double, 3 > C_u
Output.
Definition VonKarmanTurbulence.hpp:113
std::array< std::array< double, 4 >, 4 > A_v
Definition VonKarmanTurbulence.hpp:117
std::array< double, 4 > B_v
Definition VonKarmanTurbulence.hpp:118
std::array< std::array< double, 4 >, 4 > A_w
Definition VonKarmanTurbulence.hpp:123
std::array< double, 4 > C_v
Definition VonKarmanTurbulence.hpp:119
std::array< std::array< double, 3 >, 3 > A_u
State transition.
Definition VonKarmanTurbulence.hpp:111
std::array< double, 3 > B_u
Input.
Definition VonKarmanTurbulence.hpp:112
double D_v
Definition VonKarmanTurbulence.hpp:120
double D_w
Definition VonKarmanTurbulence.hpp:126
double D_u
Feedthrough.
Definition VonKarmanTurbulence.hpp:114
std::array< double, 4 > B_w
Definition VonKarmanTurbulence.hpp:124
von Kármán filter state (higher order than Dryden)
Definition VonKarmanTurbulence.hpp:76
std::array< Scalar, 3 > x_u
Longitudinal filter states (3rd order).
Definition VonKarmanTurbulence.hpp:77
std::array< Scalar, 4 > x_w
Vertical filter states (4th order).
Definition VonKarmanTurbulence.hpp:79
std::array< Scalar, 4 > x_v
Lateral filter states (4th order).
Definition VonKarmanTurbulence.hpp:78
Turbulent gust velocities in body frame.
Definition WindTypes.hpp:46
Turbulence intensity and scale parameters (MIL-F-8785C).
Definition WindTypes.hpp:73
Scalar sigma_u
Longitudinal RMS intensity [m/s].
Definition WindTypes.hpp:74
Scalar sigma_v
Lateral RMS intensity [m/s].
Definition WindTypes.hpp:75
Scalar L_w
Vertical scale length [m].
Definition WindTypes.hpp:79
Scalar L_u
Longitudinal scale length [m].
Definition WindTypes.hpp:77
Scalar L_v
Lateral scale length [m].
Definition WindTypes.hpp:78
Scalar sigma_w
Vertical RMS intensity [m/s].
Definition WindTypes.hpp:76