Математика процесса моделирования повреждений¶
Этот документ собирает все формулы подсистемы повреждений в одном месте: от обозначений и эволюции состояния до окончательного вида ОДУ 6-DoF с учётом повреждений. Сокращения: ЛА — летательный аппарат, ЦМ — центр масс, ОДУ — обыкновенное дифференциальное уравнение, MAC — Mean Aerodynamic Chord (средняя аэродинамическая хорда).
- Обзор и быстрый старт — Моделирование повреждений ЛА.
- Устройство кода и проработанные примеры — Реализация и примеры.
- Реализация формул лежит в
tensoraerospace/aerospacemodel/f16/nonlinear/damage/recompute.pyиaero_corrections.py.
Обозначения и единицы¶
Все векторы заданы в связанной (body-fixed) системе координат: \(x\) — вперёд, \(y\) — вправо, \(z\) — вниз.
| Символ | Смысл | Единицы |
|---|---|---|
| \(\mathcal{S} = \{s_1, \ldots, s_N\}\) | множество секций (\(N=13\) для F-16) | — |
| \(f_s \in [0, 1]\) | текущая доля потери секции \(s\) (section_loss) |
— |
| \(m_s\), \(A_s\), \(c_s\) | номинальная масса, площадь, хорда секции | кг, м², м |
| \(\mathbf{r}_s = (x_s, y_s, z_s)^\top\) | положение ЦМ секции в связанной СК | м |
| \(\mathbf{I}^{loc}_s = (I^{loc}_{xx,s},\,I^{loc}_{yy,s},\,I^{loc}_{zz,s},\,I^{loc}_{xy,s})\) | локальный тензор инерции относительно ЦМ секции | кг·м² |
| \(C_{l\alpha,s}\) | посекционный наклон кривой подъёма | 1/рад |
| \(C_{D0,s}\) | посекционный вклад в коэффициент паразитного сопротивления | — |
| \(\alpha\), \(\beta\) | углы атаки и скольжения | рад |
| \(S_{base}\), \(b_{base}\), \(\bar{c}_{base}\) | базовые площадь, размах, MAC исходной геометрии | м², м, м |
| \(\Delta m_{struct}\), \(\Delta \mathbf{r}_{struct}\), \(\Delta \mathbf{J}_{struct}\) | структурные поправки (сброс груза, обледенение) | кг, м, кг·м² |
Соглашение об обозначениях моментов и числа Маха
В этом документе \(M_x, M_y, M_z\) — безразмерные коэффициенты
моментов крена, тангажа и рыскания соответственно (то же, что
\(C_l, C_m, C_n\) в западной нотации; в коде —
mx, my, mz). Скалярное \(M\) без индекса — число Маха. Чтобы
избежать путаницы, в математических формулах число Маха
встречается только как параметр базовых табличных коэффициентов
\(C_y^{base}(\alpha, M, \ldots)\) и не имеет собственного раздела.
Раскладка 13 секций F-16¶
Все формулы ниже опираются на разбиение ЛА на 13 именованных секций:
6 сегментов крыла (по 3 на каждую сторону: *_root, *_mid, *_tip),
2 половины стабилизатора, киль (vtail), 3 управляющие поверхности
(rudder, aileron_left, aileron_right) и одна агрегированная
секция фюзеляжа (fuselage_main). Каждая секция имеет фиксированные
геометрические и массово-инерционные характеристики из калибровочного
файла f16_geometry.yaml — именно их перебирают суммы \(\sum_s\) во всех
формулах ниже.
Численные значения (площадь, координаты, массы, посекционные
коэффициенты \(C_{l\alpha,s}\), \(C_{D0,s}\)) подобраны так, чтобы при
\(f_s = 0\) ∀ \(s\) агрегированные параметры совпадали с baseline-значениями
F16AngularParameters (полная масса 9295,44 кг, площадь крыла
27,87 м², MAC 3,45 м) с точностью ~1 % по массе и площади и ~5 % по
тензору инерции — это инвариант калибровки.
Схема ниже показывает 13 секций в виде сверху с именами и габаритами;
эта же раскладка используется при срабатывании события section_loss,
когда поле section_name события указывает на конкретный
прямоугольник на схеме.
Эволюция состояния повреждения по времени¶
Состояние повреждения \(\mathbf{D}(t)\) — кусочно-постоянная во времени функция, обновляющаяся скачками только в моменты срабатывания событий. Пусть \(\mathcal{E}_k = \{e \in \mathcal{P} \cup \mathcal{P}_{inj} : t_{k-1} < t_e \le t_k\}\) — множество событий из расписанного профиля и инжектированных одноразовых событий, попавших в окно интегратора \((t_{k-1}, t_k]\). Тогда
где \(\Phi_e\) — оператор применения события \(e\) к состоянию (мутация
section_loss, control_failures, engine или structural), а \(\oplus\)
— бинарная операция композиции, соответствующая ассоциативному наложению
изменений в порядке вставки. Если \(\mathcal{E}_k = \emptyset\), то
\(\mathbf{D}(t) = \mathbf{D}(t_{k-1})\) и пересчёт параметров не
выполняется (важная оптимизация: бит-в-бит идентичность с baseline без
повреждений).
Эффективная масса и центр масс¶
Эффективная масса каждой секции — линейное понижение по доле потери:
Полная масса ЛА с учётом структурной поправки:
Центр масс — массово-взвешенное среднее уцелевших секций плюс структурный сдвиг:
Симметричная потеря (например, обе законцовки) сохраняет \(y_{cg} = 0\), поскольку слагаемые с \(\pm y_s\) сокращаются. Асимметричная потеря порождает ненулевой \(y_{cg}\), что становится драйвером дисбаланса крена.
Числовой пример — потеря левой законцовки на 100 %¶
Для конкретного срабатывания WING_STRIKE_LEFT_TIP (section_name ="left_tip", loss_fraction = 1.0) с использованием значений из
f16_geometry.yaml:
| Величина | Baseline | После события | \(\Delta\) |
|---|---|---|---|
| Масса \(m\), кг | 9295,44 | 9195,44 | \(-100\) (\(-1{,}1\,\%\)) |
| Площадь крыла \(S\), м² | 27,90 | 24,25 | \(-3{,}65\) (\(-13{,}1\,\%\)) |
| Размах \(b\), м | 8,60 | 7,10 | \(-1{,}50\) (\(-17{,}4\,\%\)) |
| MAC \(\bar c\), м | 3,452 | 3,673 | \(+0{,}221\) (\(+6{,}4\,\%\)) |
| \(y_{cg}\), м | 0,000 | \(+0{,}047\) | сдвиг ЦМ вправо |
Подсчёт \(y_{cg}\) — взвешенная сумма по уцелевшим секциям (вклады секций с \(y_s = 0\) и симметричных пар отбрасываются, остаётся только несимметричный вклад правой законцовки \(m_{rt}\,y_{rt} = 100 \cdot 4{,}30 = 430\) кг·м):
Этот сдвиг становится плечом результирующей подъёмной силы относительно ЦМ — отсюда возникает нескомпенсированный момент крена, который мы получим в strip-theory ниже.
Кривые пересчёта при сим/асим потере¶
График ниже показывает поведение четырёх ключевых параметров (\(m\), \(S\), \(J_x\), \(y_{cg}\)) как функцию доли потери законцовки \(f\). Синяя линия — симметричная потеря (одинаково обе законцовки): \(m\), \(S\) и \(J_x\) спадают линейно, а \(y_{cg}\) остаётся точно в нуле — ось симметрии сохранена. Красная линия — асимметричная потеря (только левая): \(m\) и \(S\) спадают вдвое медленнее (теряется только одна секция вместо двух), но \(y_{cg}\) растёт линейно с \(f\) — это и есть драйвер крен-дисбаланса.
Аэродинамические агрегаты¶
Эффективная площадь крыла суммирует только секции типа wing:
Эффективный размах — сумма расстояний до самой дальней уцелевшей точки на каждой стороне (выдерживает асимметричные потери, при которых на одной стороне крыло короче):
Если на стороне нет уцелевших секций (\(f_s = 1\) для всех), соответствующее \(\max\) берётся по пустому множеству и трактуется как 0 (полная потеря полукрыла).
Средняя аэродинамическая хорда (MAC) — площадно-взвешенное среднее хорд по уцелевшей площади:
при \(S = 0\) (полная потеря крыла) принимается \(\bar{c} = 0\).
Тензор инерции через теорему Гюйгенса-Штейнера¶
Для каждой секции применяем теорему параллельных осей, привязывая локальную инерцию к текущему ЦМ ЛА \(\mathbf{r}_{cg}\). Обозначим \(\mathbf{r}'_s = \mathbf{r}_s - \mathbf{r}_{cg} = (r_x, r_y, r_z)_s\) — смещение ЦМ секции относительно ЦМ ЛА. Локальные моменты инерции масштабируются на \((1 - f_s)\) в предположении однородной плотности секции (потеря 30 % массы → потеря 30 % её собственного \(I^{loc}\)):
Знак off-diagonal члена +m·rx·ry соответствует определению
\(J_{xy} = \int x\,y\,dm\) (не \(-\int x\,y\,dm\)): эта конвенция согласована с
F16AngularParameters.Jxy = 1331.4 и со структурой \(f16\_ode\_6dof\),
где Jxy (а не Jxz) активный off-diagonal — отличие от стандартной
западной аэрокосмической записи.
Strip-theory: дельты аэродинамических коэффициентов¶
После каждого срабатывания события базовые таблицы коэффициентов F-16 (\(C_y^{base}, C_x^{base}, \ldots\), функции \(\alpha, \beta, M, \delta_{ail}, \ldots\)) не модифицируются. Вместо этого подсистема производит аддитивные безразмерные дельты, нормированные на базовую (доповрежденческую) геометрию \(S_{base}\) и \(b_{base} = 2\,\max_{s \in \mathcal{W}} |y_s|\).
Подъёмная сила. Каждая повреждённая секция крыла теряет долю своего вклада \(C_{l\alpha,s}\,\alpha\), а вес секции — отношение её площади к базовой:
Знак минус: повреждение отнимает подъёмную силу.
Сопротивление с моделью «рваного края». Сопротивление включает два эффекта: (1) потеря посекционного \(C_{D0,s}\) при полной потере секции снижает паразитное сопротивление, (2) частично разрушенная секция добавляет дополнительное сопротивление от рваной кромки, максимальное при \(f = 0.5\) (когда экспонируется максимальная площадь среза):
где \(k_J = 0{,}05\) — калиброванный эвристический коэффициент. Парабола \(f(1-f)\) имеет максимум \(0{,}25\) при \(f = 0{,}5\), что соответствует физической интуиции: целая или полностью оторванная секция обтекается чисто, а полусрезанная даёт максимум турбулентного сопротивления.
Боковая сила доминируется потерей вертикального оперения:
где \(\mathcal{V}\) — секции типа vtail. Коэффициент \(k_{vt}\) откалиброван
так, что полная потеря киля даёт \({\partial C_z}/{\partial\beta} \approx 0{,}40\),
что соответствует реальному вкладу вертикального оперения F-16 в боковую
устойчивость.
Момент крена возникает только при асимметрии — каждая секция вносит свой плечевой момент \(y_s/b_{base}\):
Симметричная потеря: \(y_s\) для левой и правой секций имеют противоположные
знаки, и слагаемые сокращаются → \(\Delta M_x = 0\). Асимметричная потеря
(например, только left_tip): остаётся ненулевой результирующий
\(\Delta M_x\), пропорциональный и \(\alpha\), и \(f\) — это и есть драйвер
дисбаланса крена в WING_STRIKE_LEFT_TIP.
Момент тангажа учитывает плечо \(x_s\) от ЦМ до аэродинамического центра секции (поэтому в формулу включаются как крылья, так и стабилизатор):
где \(\mathcal{T}\) — секции типа stab, \(x^{arm}_s\) — aero_x_arm
(плечо от ЦМ ЛА до аэродинамического центра секции).
Момент рыскания — асимметричное сопротивление вокруг \(z\):
где \(\delta C_{x,s}\) — посекционный вклад в \(\Delta C_x\) (включая рваный край для секций крыла).
Числовой пример — \(\Delta C_y\) и \(\Delta M_x\) при потере законцовки¶
Для того же срабатывания WING_STRIKE_LEFT_TIP (\(f_{left\_tip} = 1{,}0\),
остальные \(f_s = 0\)) при типичном крейсерском \(\alpha = 5° = 0{,}0873\)
рад, используя \(C_{l\alpha,\,left\_tip} = 3{,}40\) 1/рад,
\(A_{left\_tip} = 3{,}65\) м², \(S_{base} = 27{,}87\) м², \(y_{left\_tip} =
-4{,}30\) м, \(b_{base} = 8{,}60\) м:
При базовом \(C_y^{base}(\alpha = 5°) \approx 0{,}393\) потеря составляет \(\Delta C_y / C_y^{base} \approx -9{,}9\,\%\) — заметная просадка подъёмной силы. Положительный \(\Delta M_x\) соответствует крен-моменту на правое полукрыло (поскольку левое потеряло свою долю подъёмной силы) — именно это и видит управляющий агент в виде растущего \(\omega_x\) после срабатывания события.
Графическая иллюстрация дельт¶
Левая панель ниже показывает \(\Delta C_y\) как функцию \(\alpha\) для симметричной потери обеих законцовок: коэффициент линеен по \(\alpha\) и масштабируется с \(f\) (здесь — 60 %), типичное значение при \(\alpha = 10°\) — около \(-0{,}10\), то есть \(\sim 12\,\%\) от здоровой подъёмной силы. Правая панель — \(\Delta M_x\) для асимметричной (только левой) потери: ненулевой, тоже линеен по \(\alpha\) и пропорционален \(f\) — это и есть драйвер вращения по крену.
Сравнительная схема ниже собирает оба сценария в одну картинку: симметричная потеря (слева) сохраняет балансировку и снижает только подъёмную силу; асимметричная потеря (справа) дополнительно вносит сдвиг ЦМ и момент крена, растущий с долей потери \(f\) — качественное различие, о котором говорят формулы \(\Delta M_x\) и \(\mathbf{r}_{cg}\) выше.
Отказы рулевых поверхностей¶
Команды актюатору \(\mathbf{u}_{cmd}\) преобразуются в эффективные
\(\mathbf{u}_{eff}\) до интегратора через посимвольное отображение
apply_control_failures(u, state):
Здесь \(\eta_i\) — поле efficiency объекта ControlFailure, \(u^{jam}_i\)
— поле jam_position_rad. Несколько отказов на одном индексе
компонуются в порядке вставки в state.control_failures. Для split-stab
режима (\(\mathbf{u} \in \mathbb{R}^4\)): индексы stab_left=0,
stab_right=1, aileron=2, rudder=3.
Двигатель¶
В текущей угловой ОДУ воздушная скорость считается константой, поэтому
\(T_{eff}\) читается потребителями отдельно через хелпер
effective_thrust(base_thrust, state) из damage/propulsion.py —
им пользуются, например, RL-награды и расширения динамики. Полный учёт
тяги в самих ОДУ — задача будущего расширения.
Связь с уравнениями движения¶
В каждой точке интегратора полные коэффициенты получаются как сумма табличного значения и текущей дельты:
Уравнения движения 6-DoF в связанной СК с обновлёнными \(m\), \(\mathbf{J}\), \(S\), \(\bar{c}\), \(b\) принимают вид (упрощённо, для иллюстрации связи):
где \(q = \tfrac{1}{2}\rho V^2\) — скоростной напор, а тензор \(\mathbf{J}\) —
теперь функция времени, поскольку при каждом срабатывании события
пересчитывается apply_to_params(...). Все векторы и моменты заданы в
связанной (body-fixed) СК, как и состояние ЛА. Именно эта замена
\(\mathbf{J}_{base} \to \mathbf{J}(t)\), \(\mathbf{F}_{aero} \to \mathbf{F}_{aero} + \Delta\mathbf{F}\),
\(\mathbf{u}_{cmd} \to \mathbf{u}_{eff}\) и превращает объект управления
F-16 с фиксированными параметрами в объект с параметрами,
зависящими от времени (кусочно-нестационарный — параметры меняются
скачками в моменты событий и постоянны между ними).
Проработанный пример: WING_STRIKE_LEFT_TIP в полёте¶
В этом разделе мы прогоняем через все формулы выше один конкретный
сценарий: пресет WING_STRIKE_LEFT_TIP — мгновенная полная потеря
левой законцовки left_tip на \(t = 10\) с при горизонтальном полёте с
постоянным \(\alpha = 5°\) и нулевой командой РУС. Цель — показать, как
последовательное применение формул из предыдущих разделов даёт
наблюдаемое поведение объекта управления.
Состояние повреждения и оператор события¶
Профиль состоит из одного события:
Оператор \(\Phi_e\) изменяет только одно поле состояния:
прочие поля (control_failures, engine, structural) остаются
дефолтными. На шаге интегратора, накрывшем \(t = 10\) с, срабатывает
\(\mathcal{E}_k = \{e\}\) и запускается полный пересчёт параметров через
apply_to_params(...).
Шаг 1. Эффективная масса, ЦМ и геометрия¶
После применения формул для \(m^{eff}_s\) и агрегирования:
| Параметр | Значение | Δ к baseline |
|---|---|---|
| \(m\) | 9195,44 кг | \(-100\) кг (\(-1{,}1\,\%\)) |
| \(S\) | 24,25 м² | \(-3{,}65\) м² (\(-13{,}1\,\%\)) |
| \(b\) | 7,10 м | \(-1{,}50\) м (\(-17{,}4\,\%\)) |
| \(\bar{c}\) | 3,673 м | \(+0{,}221\) м (\(+6{,}4\,\%\)) |
| \(y_{cg}\) | \(+0{,}047\) м | сдвиг вправо |
| \(x_{cg}\), \(z_{cg}\) | без изменений | — |
Подсчёт \(b\): размах правой стороны без изменений (\(\max |y| = 4{,}30\) м
у right_tip), а на левой стороне самая дальняя уцелевшая секция —
теперь left_mid с \(|y| = 2{,}80\) м, так что \(b = 4{,}30 + 2{,}80 =
7{,}10\) м.
Шаг 2. Тензор инерции¶
Для \(J_{xx}\) изменения сводятся к двум вычитаемым компонентам:
вкладу left_tip через локальную \(I^{loc}_{xx}\) и через
параллельно-осевой член \(m \cdot (r_y^2 + r_z^2)\):
вместо baseline-вклада \(220 + 100 \cdot (4{,}30^2 + 0{,}02^2) \approx 220 + 1849 = 2069\) кг·м². Plus небольшие сдвиги во всех остальных секциях из-за изменения опорного \(\mathbf{r}_{cg}\) (величина \(r'_s = \mathbf{r}_s - \mathbf{r}_{cg}\) слегка меняется для каждой секции). \(J_{xy}\) перестаёт быть нулевым, поскольку \(y_{cg} \neq 0\) — конкретное число зависит от полной суммы и обычно невелико для этого сценария.
Шаг 3. Strip-theory дельты в установившемся режиме¶
При \(\alpha = 5° = 0{,}0873\) рад (\(\beta = 0\)):
Доминируют два эффекта: просадка \(C_y\) (на ~10 % при крейсерском \(\alpha\)) и появление ненулевого \(\Delta M_x\) — именно из-за ненулевого плеча \(y_{lt}/b_{base} = -0{,}5\).
Шаг 4. Подстановка в ОДУ¶
В момент \(t > 10\) с шаг ОДУ выполняется с обновлёнными параметрами:
Член \(\mathbf{F}_{aero}\) потерял ~10 % подъёмной силы → ЛА начинает проседать по высоте; член \(\mathbf{M}_{aero}\) получил ненулевой \(M_x\)-компонент при \(\boldsymbol{\omega} \approx 0\) → \(\dot{\omega}_x = M_x \cdot q \cdot S \cdot b / J_{xx} > 0\), и угловая скорость крена накапливается линейно.
Шаг 5. Наблюдаемая траектория¶
Графики ниже — результат численного интегрирования с этими параметрами
(скрипт-демо example/failure_demos/f16_damage_dogfight_demo.py). До \(t = 10\) с —
здоровый ЛА в горизонте; после \(t = 10\) с в повреждённом прогоне
(оранжевая линия) явно видна угловая скорость крена \(\omega_x\),
которая в здоровом прогоне (синяя) остаётся при нуле. Это и есть
прямое следствие \(\Delta M_x \neq 0\) из шага 3. Параллельно \(\alpha\)
дрейфует — уменьшение подъёмной силы заставляет ЛА снижаться, что
меняет угол атаки. Тангаж \(\omega_z\) и руль высоты остаются в
здоровых диапазонах: потеря \(\texttt{left\_tip}\) к оси тангажа не
привязана.
Шаг 6. Что видит RL-агент¶
Если агент обучается с damage_observable=False, он не получает явных
сигналов о повреждении — только изменившуюся динамику: новый
коэффициент усиления по руль-высоте → α (потому что \(S\) и \(\bar{c}\)
другие), ненулевую корреляцию команда-крен (которой раньше не было),
и общий тренд α на снижение. Адаптивные алгоритмы (iADP, AIDI,
ET-DHP) идентифицируют новые \(\tilde F, \tilde G\) через невязки RLS
или event-trigger обновления; неадаптивные обученные политики (PPO,
SAC) могут деградировать — степень зависит от того, насколько
повреждённые состояния попадали в распределение обучения.
Сводный вычислительный цикл¶
На каждом шаге интегратора:
damage_manager.update(t_curr, t_prev)собирает \(\mathcal{E}_k\).- Если \(\mathcal{E}_k \neq \emptyset\): применяются операторы \(\Phi_e\),
затем
apply_to_paramsпересчитывает \(m, S, b, \bar{c}, \mathbf{r}_{cg}, \mathbf{J}\). apply_control_failures(u_cmd, state)→ \(\mathbf{u}_{eff}\).f16_ode_6dofвычисляет \(C^{base}_*\) из таблиц по \(\alpha, \beta, M\) и добавляет \(\Delta C_*\) черезdelta_cy/cx/cz/mx/my/mz(α, β, geo, state).- ОДУ интегрируется (Euler / RK4) с обновлёнными \(m, \mathbf{J}\) и полными \(C_*\).
Стоимость пересчёта — \(O(N)\) по числу секций (\(N=13\)), и он выполняется
только в шагах со срабатываниями. На остальных шагах кэшированные
параметры читаются напрямую — это обеспечивает бит-в-бит совместимость с
исходным baseline без damage_profile.




