Модель воздуха в трёх масштабах
План и задачи — docs/plan/air_model.md; журнал — docs/archive/plan/air-model-progress.md. Здесь —
описание того, что уже работает в игре.
Поле на CPU (масштаб 1 → игра)
Среднее поле воздуха (решение Пикара, масштаб 1) в игре читается на CPU: air_velocity_at
зовут физика крыла (3 точки × 120 Гц), боты, птицы, колдун. Код:
scripts/atmosphere/air_model/wind_field.gd (WindField — один уровень),
scripts/atmosphere/air_model/air_field_set.gd (AirFieldSet — набор уровней и подмена),
подключение — scripts/atmosphere/atmosphere.gd. Тесты — tests/atmosphere/test_wind_field.gd
(на аналитических массивах), tests/atmosphere/test_air_model_atmo.gd (атмосфера с полем
прикидки Онгудая).
Раскладка
Сетка — декартова MAC с маской «клетка под землёй» (решение AM-01,
tools/research/air3d/reference.md → «Решение: σ-сетка или маска»), Δz постоянный на уровне.
На CPU поле хранится в центрах клеток (решатель отдаёт скорости на гранях; перенос в центры —
среднее двух граней, как centers() решателя, — делает WindField.from_mac). Центры выбраны,
потому что выборка тогда одна и та же для всех каналов (трилинейно по 8 узлам), а точность
интерполяции на гранях и в центрах одного порядка.
- Массив (nz, ny, nx), индекс (k·ny + j)·nx + i, float32. i — восток (x мира), j — север (y = −Z мира), k — вверх (высота над морем). Так же лежат массивы решателя и эталоны AM-01.
- Центр клетки: x = x0 + (i + ½)·dx, y = y0 + (j + ½)·dx, z = z_bot + (k + ½)·dz; x0, y0 — западный и южный края в координатах решателя (мир: Z = −y).
- Клетка под землёй, если z её центра < hc столбца (hc — высота рельефа сетки, блочное среднее по клетке); первая воздушная клетка столбца k₁ = ⌈(hc − z_bot)/dz − ½⌉.
- Каналы: u, v (восток, север), w_mech — вертикаль решения без нагрева (обтекание рельефа
ветром), w_conv = w − w_mech (от нагрева), θ′ (К). Разделение — вторым решением без нагрева
(
docs/plan/air_model.md→ «Стык 1 ↔ 2»). - Метаданные: dx, dz, x0, y0, z_bot, nx, ny, nz, z0 (шероховатость решателя, 0,1 м).
Построение:
WindField.from_arrays(meta, u, v, w_mech, w_conv, theta, hc, max_speed, max_w)— массивы в центрах; через него отдают поле GPU-решатель (AM-03) и библиотека полей (AM-06б). NaN и ∞ → 0, ограничители — за тот же проход. Проход O(n) в GDScript: окно 64 × 64 × 62 (254 тыс. клеток) читается и строится за ~0,18 с — строить в рабочем потоке (класс не трогает сцену), в главном — толькоset_field.WindField.from_mac(meta, u, v, w, w_mech_faces, theta, cell, hc)— массивы решателя на гранях с ореолом (NZ, NY, NX) = (nz + 2, ny + 2, nx + 2), как эталоны AM-01 (fixtures.py).WindField.load_file(путь)—<путь>.json(метаданные,arrays: {имя: [смещение, длина]}в числах float32, как у эталонов AM-01) +<путь>.bin(float32 LE). Конвертер полей прикидки (npz окна 100 м) —tools/research/air3d/to_game_field.py.
Выборка
WindField.sample(pos, ground_h) -> Vector3 — мир (x — восток, y — вверх = w_mech, z — юг = −v):
- Точка → дробные индексы центров; берутся 4 соседних столбца (за краем — ближайший край).
- Высота у земли — по настоящей высоте над рельефом. Рельеф сетки (блочное среднее 100 м)
отличается от настоящего на десятки метров. Столбец c читается на высоте
z_c = y + (hc_c − h)·exp(−agl/dx), где h — настоящая земля под точкой (атмосфера передаёт
ground.sample().x), agl = y − h. У земли пилот на 20 м над настоящей землёй читает поле на 20 м над землёй сетки; выше подсеточные неровности гаснут на масштабе клетки (возмущение от неровности размера L затухает с высотой ~ L — потенциальное обтекание), и выборка идёт по абсолютной высоте. Выборка не «проваливается под землю» соседнего столбца на склоне. - По вертикали — линейно между центрами клеток; ниже центра первой воздушной клетки — логарифмический профиль к нулю на z0: значение первой клетки × ln(a/z0)/ln(a₁/z0), a — высота над hc столбца, a₁ — высота центра первой клетки (так же решатель считает трение о землю, C_d = (κ/ln(Δz/2/z0))²). Для θ′ — значение первой клетки (без профиля). Выше верха — верхний уровень.
- Билинейно по 4 столбцам. Столбец целиком под землёй даёт 0.
Итог: на ровном месте выше первых клеток — точная трилинейная интерполяция (линейное поле
воспроизводится до 5·10⁻⁷ м/с, тест). sample_theta, sample_w_conv — то же для θ′ и w_conv.
Край: edge_weight(pos) — 1 внутри, в полосе edge_blend_cells клеток у боковых граней (dx) и
под верхом (dz) плавно (smoothstep) до 0 на границе. contains(pos) — точка внутри по
горизонтали и между низом и верхом сетки.
Ограничители (clamp_values: при построении и при подаче поля с другими пределами): |горизонталь| ≤ max_speed_ms,
|w_mech|, |w_conv| ≤ max_w_ms — защита от нефизичного решения; в полях прикидки не срабатывают.
Уровни и подмена (AirFieldSet)
levels— уровни от мелкого к грубому (клипмапы AM-04: окна 50/100 м, область 400 м). Выборка: мелкий с весом края w₁, остаток (1 − w₁) — следующему, …; что не покрыто — аналитике.sample(pos, ground_h) -> Vector4: xyz — сумма вкладов (м/с), w — доля поля 0..1. Стык уровней — плавный (в тесте: окно 100 м в области 400 м, скачок < 0,05 м/с на 1 м).set_field(поле | [уровни] | null, blend_s)— подмена: новое поле за blend_s секунд времени атмосферы смешивается со старым, доля нового — smoothstep(t/blend_s), монотонно. Старым может быть «нет поля» (аналитика) — так же плавно поле включается и выключается. Время идёт вAtmosphere.step(advance(dt)). Подмена нужна для пересчёта поля каждыеrecompute_game_minигровых минут и при смене ветра/погоды (AirRuntime, ниже).- Подмена во время подмены: «старым» становится снимок текущей смеси (взвешенная сумма наборов уровней, не больше трёх) — выборка не скачет, как бы часто ни приходили новые поля.
Клипмапы (AM-04)
Три уровня: область 400 м (38,4 км, всё место) и два окна 64 × 64 вокруг пилота —
100 м (6,4 км) и 50 м (3,2 км), Δz = Δx/2. Окно решается тем же Пикаром с границей от
уровня крупнее (область → окно 100 м → окно 50 м): у краёв окна поле тянется к родителю (зона
релаксации 4 клетки), поэтому на стыке нет ступеньки, а внутри окно видит рельеф в своём
разрешении (склон, бровка, седловина). При загрузке места все окна считаются с центром на старте;
в полёте, когда пилот ушёл от центра окна на четверть его стороны (air_model.window_shift_frac),
окно и все мельче пересчитываются фоном с центром у пилота (≈ 1–3 с после сдвига, кадр не
стоит), до готовности игра берёт прежние уровни, готовый набор подменяется плавно (blend_s).
Термики берут источники с области (подпись сетки для сети при сдвиге окон не меняется).
Стык (Каянча, 12:00, 3 м/с; tools/research/air_clipmap/out/seam_kayancha_h12_U3.png): что видит
пилот, пересекая край окна, меняется не быстрее, чем внутри окна над тем же рельефом — за 50 м
до 9–12 % скорости на 50 м над землёй (внутри 9–18 %), 1–5 % на 300 м (внутри 1–2 %). Сами уровни у
земли различаются на 6–18 % (разрешение рельефа: 400 м занижает разгон на склонах) — полоса края
(5 клеток) сглаживает эту разницу. Подробно — docs/guide/air-model-gpu.md → «Клипмапы».
Стык с атмосферой (правило «Стык 1 ↔ 2»)
В Atmosphere.air_velocity_at при включённом поле (доля fw.w > 0):
- горизонталь — из поля: fw.xz + (1 − fw.w)·аналитика (профиль ветра × высота над морем);
- механическая вертикаль w_mech — из поля вместо аналитического склонового подъёма
w_ridge(в доле 1 − fw.w у края —w_ridge); - конвективная w_conv пилоту не отдаётся — её отдадут пузыри термиков (AM-07). До AM-07 термики и фоновое опускание работают как раньше (поверх поля).
- Масштаб 3 (подветренная зона, болтанка) — по полю, см. «Масштаб 3: возмущения из поля» (AM-08): подветренное опускание и ослабление ветра — только из поля (двойной счёт снят), эвристика за гребнем даёт болтанку слоя смешения по ветру на уровне гребня, рывки (часть болтанки, с нулевым средним) и обратный поток у земли — только где пузырь отрыва сеткой не разрешён; грозы, волны, облака — как в аналитике.
mean_wind_at— тот же вес поля: горизонталь поля + w_mech (без подветренной эвристики и шума); без поля — как раньше (вертикаль 0). Порывистость травы (air − mean) не ловит разгон поля.
Выключенное поле — побитно прежняя аналитика: ветка поля не выполняется
(tools/bench/air_velocity_bench.gd --compare: 38 400 значений, 0 отличий; тест
test_off_and_outside_bitwise_analytic — и вне поля).
Конфиг (configs/atmosphere.json → air_model)
| Ключ | По умолчанию | Смысл |
|---|---|---|
enabled | "auto" | auto — поле, если есть, иначе аналитика; on — требовать (нет — аналитика и предупреждение); off — всегда аналитика |
edge_blend_cells | 5 | полоса края, клеток уровня (окно 100 м — 500 м, область 400 м — 2 км, как губки решателя) |
blend_s | 60 | время плавной подмены поля, с времени атмосферы |
recompute_game_min | 15 | пересчёт поля по игровому времени, мин (и при смене ветра/погоды) |
timeout_s | 60 | предел одного расчёта поля, с стены; превышен — аналитика (загрузка) / прежнее поле (полёт) |
max_speed_ms, max_w_ms | 40, 10 | ограничители |
API атмосферы: set_air_field(поле | [уровни] | null, blend_s = -1) (−1 — blend_s из конфига),
set_air_mode("auto" | "on" | "off") (отладка «поле/аналитика», замеры), is_air_field_on(),
air_field (AirFieldSet: θ′ и w_conv для масштабов 2 и 3). Поле переживает configure().
Запасной путь и детерминизм
- Поля нет (headless, нет GPU, ошибка расчёта или чтения, таймаут) → нынешняя аналитика; в
журнал одна строка на смену режима:
air_model: analytic (<причина>)илиair_model: field (<источник>; уровней N). AtmoFingerprint.make_worldставитair_model.enabled = "off"→ отпечаток детерминизма иtest_determinismне зависят от видеокарты и поля. Поле в ключ мира не входит.
Загрузка и пересчёт поля (AirRuntime, AM-06Б)
scripts/atmosphere/air_model/air_runtime.gd — узел-ребёнок Game; интерфейс — контракт C9
(docs/contracts/air-model.md). Один уровень — область 400 м (38,4 × 38,4 км вокруг центра
места); окна 100/50 м вокруг пилота добавит AM-04 тем же путём.
Нейросеть вместо решателя (air_model.engine = "nn", ON-5, O5/O6). Тот же узел и те же сроки; проход — одна
задача рабочего потока (AirNnField.run_pass): AirPlace.domain_case → AirNnInput (строка, страж области) →
AirNnPrep (карты, числа) → AirOnnx.run (CPU) → to_physical → WindField на сетке решателя (13 AGL → центры
клеток по высоте, выше 2 км отклонения от притока гаснут к 3 км). Окон нет (один уровень), GPU не нужен, работает
headless; два прохода k — как у решателя. Файл сети: --air-nn-model= → user://air_nn/model.onnx →
air_model.nn_model. Отказ (нет расширения, файла, формат ≠ O1, ORT, NaN) — air_model: analytic (нейросеть: …).
Как вставить сеть и полетать — data/air_nn/README.md. Замер: tools/air_onnx/nn_load_probe.sh <model.onnx>. Пункт настроек «Ветер над рельефом»: расчёт / упрощённый / нейросеть.
Загрузка. Этап «Рассчитываем ветер» / “Computing wind” (LoadProgress, ключ wind, вес в
configs/ui.json → loading.stage_weights) — после этапа «Камни, кусты и дороги», когда известен
ветер у старта (встречный на старте — по курсу старта), до расстановки термиков (их источники —
из поля). Поле — всегда точное для часа старта, ветра (u10 — ветер прогноза на 10 м у старта,
направление атмосферы) и погоды полёта (дневной максимум и небо из прогноза пилота); подаётся
в атмосферу сразу, без подмены. Доля полоски — по ходу решателя. Встроенные места, места с карты
и сетевая игра — одинаково: в сети каждый клиент считает поле сам в Game.start, общие у всех
только источники термиков (их шлёт ведущий, C5). То же место и те же условия («Ещё раз») — этап
мгновенный, поле уже в атмосфере.
Порядок и где идёт работа:
- вход решателя (
AirPlace.domain_case: рельеф блоками, погода на час, солнце по склонам) и подготовка обоих решений (AirCase.prepare, с нагревом и без) — рабочий поток, ~1,2 с; - решатель (
AirPicardJob,mech = true) — главный поток порциями: на экране загрузкиpoll_slice(40 мс), в полётеpoll()раз в кадр, порция GPU ≤ 25 мс; - сборка
WindField—field_async(рабочий поток), затемset_air_fieldна главном.
Локальный RenderingDevice и ядра создаются один раз при запуске игры (~0,2 с — кадр запуска и так длинный) и живут до выхода; после каждого расчёта освобождаются только его буферы (~95 МБ).
Полёт. Срок пересчёта — каждые recompute_game_min = 15 игровых минут по часам неба
(ускорение времени ×10/×60 учтено: при ×60 срок — раз в 15 с): поле считается на начало срока
(12:15, 12:30, …) с тёплого старта от состояния текущего поля и плавно подменяет его за
blend_s = 60 с времени атмосферы. Смена ветра (> 0,05 м/с или > 1°) или погоды — внеочередной
пересчёт. Очереди нет: пересчёт, не успевший до следующего срока, по окончании сразу сменяется
новым — на последний срок. Ошибка или таймаут в полёте — остаётся прежнее поле, следующая
попытка на следующем сроке; при загрузке — аналитика и строка air_model: analytic (<причина>).
Удачный расчёт — строка air_model: поле 12:15 ч, 3.0 м/с с 151° (<причина>): <с>, итераций [без нагрева, с нагревом]…; k притока …, U над стартом на 10 м … (проход 1: …), проходов N [проходы].
Поле под старт (air-start, C9 v3). Ветер меню — ветер на 10 м над стартом, а решатель задаёт
ветер притоком на краю области 38,4 км над сглаженным рельефом: над стартом (гребень, разгон
обтекания) поле при том же притоке давало 1,0–2,1 × меню на 10 м (WPC-2). Поэтому загрузка с
центром окон и ветром идёт в два прохода: проход 1 — область и окна с множителем притока k₀ (1 или k
прошлой загрузки того же места и направления), замер U₁ — горизонталь среднего поля без болтанки на
10 м над землёй старта (по набору уровней с весами края, как выборка атмосферы; земля для сдвига
поля по рельефу — сетка GroundField, как у атмосферы); k₁ = k₀·(u10/U₁)^(1/p) (пределы 0,3…3);
проход 2 с k₁ — только его поле подаётся в атмосферу. Поле не пропорционально притоку (нагретые
склоны дают ветер, не растущий с притоком; толщина слоя ∝ u*): U над стартом ∝ k^p, p — по ветру
меню 0,57 (3 м/с), 0,75 (6), 0,90 (10), между — линейно (AirRuntime.INFLOW_P, медианы по парам
проходов на 10 стартах, tools/research/air_start/out/passes.csv). Множитель — на весь профиль
притока (U10 притока, u* замыкания); α, класс устойчивости и z_sat — по ветру меню; калибровка
решателя (k = 1) не меняется. Предел timeout_s — на проход; проход 2 не удался — подаётся поле
прохода 1 (строка air_model: проход 2 не удался (<причина>) — поле прохода 1). Без окон или в
штиль (u10 < 0,5 м/с, WindProfile.U10_MIN) — один проход с k = 1. Слабый ветер: проход 1 упёрся
в предел итераций (3000) хотя бы в одном решении области или окна — второго прохода нет, подаётся
поле прохода 1 (air_model: проход 1 не сошёлся (предел итераций) — без подстройки,
last_info.not_converged). Пересчёт в полёте — один проход с k загрузки (k в полёте не
уточняется: смена часа меняет нагрев и устойчивость).
Границы модели: на 100 м над стартом поле после подстройки на 5–40 % слабее аналитики WindModel
(по Taylor & Lee 1984 аналитика здесь завышает на 10–28 %, WPC-2); на слабом ветре (≲ 3 м/с днём,
штиль) решатель не сходится за 3000 итераций — невязки импульса и θ′ решения без нагрева
перестают падать (малые u* и K, устойчивая стратификация над тонким слоем) — отдельная задача
(TODO), загрузка у таких стартов дольше и без подстройки.
Числа (RTX 4070 SUPER, Онгудай, 12:00, 3 м/с со 150°; tests/atmosphere/test_air_runtime_gpu.gd,
tools/loading/load_probe.gd --location=ongudai --hour=12 --stage-shot=wind):
| Что | Значение |
|---|---|
| этап «Рассчитываем ветер» в игре (окно 1280×720) | 3,3–3,9 с: вход места и подготовка 1,2 с (рабочий поток) + решатель 1,6–2 с (GPU 0,73 с, 100 + 90 итераций) + сборка поля |
| кадр в этапе | ≤ 94 мс от расчёта (наибольшая доля AirRuntime за кадр 54–61 мс — запуск задачи, опрос ≤ 54 мс); в половине прогонов первый кадр этапа 450–510 мс — хвост этапа «Камни, кусты и дороги» (без этапа ветра такой же кадр 1,5 с приходится на этап «Почти готово») |
| пересчёт в полёте (кадры, окно 320×240) | 3,7–4,1 с стены (GPU 0,8–1,0 с), доля AirRuntime за кадр ≤ 56 мс, опрос ≤ 13 мс, порция GPU ≤ 22 мс |
| тёплый старт | 70 + 90 итераций против 100 + 90 холодного: греется только решение без нагрева (Р13 в контрактах) |
| ускорение ×10 / ×60 | срок 90 / 15 с реального времени; пересчёт 4 с — 4,5 % / 27 % срока, успевает |
| поле AirRuntime против AirPicardJob напрямую | у старта (16 точек, 10–400 м) совпадает побитно |
| подмена через два пересчёта (второй — посреди первой подмены) | шаг w_mech ≤ 0,0004 м/с за 0,1 с; график — tools/research/air_runtime/out/blend_trace.png |
Ограничения.
- Каждое новое поле пересобирает источники термиков (
AirThermals.build) на главном потоке — ~0,8 с на область 400 м; в полёте это кадр раз в срок пересчёта. В рабочий поток — AM-11 (контракты, Р12). - Дата поля — опорная дата погоды (
reference_context), а не дата полёта (Р14). - Время этапа на слабых видеокартах (AMD — оценка ×2…×11 по памяти) — до ~15 с; предел —
timeout_s.
Отладка: полёт на поле из файла
Вместо расчёта при загрузке поле можно подать из файла — аргумент --air-field=<путь> (.json + .bin),
его читает Atmosphere один раз за запуск:
cd tools/research/air3d
PY=../heat_ca/.venv/bin/python
F=tools/research/air3d/out/fields # поля прикидки (вне git)
$PY to_game_field.py $F/W100_h13_U3_d180.npz $F/W100_noheat_U3_d180.npz fields/game/kayancha_w100_h13_U3_d180
cd ../../..
godot --path . -- --location=ongudai --wind=3 --from=180 --hour=12 \
--air-field=tools/research/air3d/fields/game/kayancha_w100_h13_U3_d180.jsonПоле прикидки — окно 100 м 6,4 × 6,4 км у Каянчи (64 × 64 × 62, 5 МБ), 13:00, южный 3 м/с; ветер игры надо задать тот же (поле его не подстраивает). Вне окна — аналитика.
Числа (AM-05)
- Выборка на аналитических массивах: постоянное поле — ошибка 0; линейное — 4,8·10⁻⁷ м/с; лог-профиль у земли — до 10⁻⁴; вес края монотонен, шаг ≤ 0,01 на 1 м; NaN во входе → конечно.
- Каянча, поле прикидки (фикстура 16 × 16 × 40 у старта), 50 м над землёй сетки:
air_velocity_at= (−0,563; 0,076; −2,455) м/с = поле (u, w_mech, −v) до 10⁻⁴; w_conv 0,103 (пилоту не отдаётся); сумма 0,18 м/с совпадает с «подъёмом у старта на 50 м» прикидки (agl_slice, 0,178). Через край окна на высоте 2400 м — изменение ≤ 0,03 м/с на 5 м. - Время
air_velocity_at(способ базы AM-00: Каянча, 75 м, 100 000 вызовов в точке): без поля 14,8 мкс, с полем 20,4 мкс (×1,37; база AM-00 — 14,3 мкс). По сетке 6400 точек в окне поля: 16,8 → 25,4 мкс (×1,5).tools/bench/air_velocity_bench.gd.
Отладка: срезы и F3 (AM-10)
- Срезы (WF-09):
tools/wind_field/dump_slices.gd+.tscn— headless-инструмент, без окна. Читает поле из файла (WindField.load_file, тот же формат, что--air-field) и рисует три PNG: два горизонтальных среза (20 и 200 м AGL; цвет — разгон |Gₕ|/U₀ − 1, редкая сетка стрелок направления) и один вертикальный вдоль ветра через точку (цвет — w/U₀, тонкие изолинии θ′ каждые 0,15 К, силуэт рельефа снизу). Термики поверх вертикального среза — по желанию (--location=<id>): текущая модель термиков черезAtmosphere.thermals_near(жёлтые треугольники по силе) — не термики из среднего поля 1 (AM-07 делает это параллельно; подпись на срезе так и говорит). Запуск:Точка среза по умолчанию — пробаgodot --headless --path . res://tools/wind_field/dump_slices.tscn -- \ --field=tools/research/air3d/fields/game/kayancha_w100_h13_U3_d180.json \ --out=tools/research/air3d/out/slices --name=kayancha --wind=3 --from=180 --hour=13 \ [--point=x,y,z] [--location=ongudai] [--extra_out=build/screenshots --extra_prefix=03]*_agl10из meta поля (обычно старт), иначе центр поля. На срезе Каянчи видны разгон и подъём над бровкой перевала (полоса подъёма/спада у земли) и явная полоса ускорения над седловиной на 200 м AGL. Вертикальный срез рисует и<имя>.json(полуширина, высота, шкала w, θ′-шаг, место/час/ветер) —tools/wind_field/annotate_slice.py(PIL) накладывает по нему оси (км / м), шкалу цвета w (м/с) и заголовок: GDScript headless без окна текст не рисует, PNG остаётся голой заливкой без подписей до этого шага.python3 tools/wind_field/annotate_slice.py \ tools/research/air3d/out/slices/kayancha_vertikal_vdol_vetra.png --out build/screenshots/04_....png - F3 в игре: отдельный узел
WindFieldDebug(scripts/atmosphere/wind_field_debug.gd), добавлен вscenes/game/game.tscnрядом сGame(без правокgame.gd) — по нажатию F3 строитMultiMeshстрелок горизонтального ветра (Atmosphere.air_velocity_at— та же выборка, что у пилота) в сетке вокруг пилота (радиус/шаг/высоты — экспорты узла), цвет — вертикаль (подъём — голубой, опускание — красный); подпись в углу экрана — «поле» или «аналитика» (is_air_field_on). Повторное F3 — выключить:_processостанавливается,MultiMeshи надпись скрыты — без выборок и перестроений, ноль влияния на FPS. F3 раньше в проекте не использовался (нет записи вconfigs/controls.json/input map — проверено, свободна). Скриншот-инструмент (нужно окно):tools/shots/wind_field_shot.gd— какcloud_shadow_shot.gd(автостарт полёта, ждёт FLYING), включает F3 черезWindFieldDebug._toggle()и снимает кадр (--shot), либо меряет среднее GPU-время кадраRenderingServerза--gpu=Nкадров (общий кадр окна — для сравнения с полем и без, не только трава/вода). Пример:XDG_DATA_HOME=$(mktemp -d) godot --path . --audio-driver Dummy --resolution 1920x1080 \ res://tools/shots/wind_field_shot.tscn -- --autostart --bots=0 --location=ongudai \ --site=kayancha_south --wind=3 --from=180 --hour=13 \ --air-field=tools/research/air3d/fields/game/kayancha_w100_h13_U3_d180.json \ --out=build/screenshots --tag=kayancha --shot --preset=high - Трава и рябь на воде по полю (WF-10):
TerrainWind(scripts/terrain/terrain_wind.gd) раз вfield_tex_interval_s(configs/world.json → wind_visual) строит 2D-текстуру RGF (u, v горизонтали нижнего слоя поля,AirFieldSet.sample) вокруг камеры и передаёт всем материалам (field_wind_tex/field_wind_origin/field_wind_size_m); источник поля — самAtmosphere, передан черезWorldLink.link→Terrain.set_wind_sources(…, field_src)(duck typing:is_air_field_on()/air_field, без правокatmosphere.gd). В шейдерах —scripts/terrain/terrain_wind.gdshaderinc(grass_wind, per-blade трава) иscripts/terrain/terrain.gdshader(water_wind, рябь) берутfield_wind_texпо месту (xz) вместо общегоwind_vec, когдаfield_wind_size_m > 0; без поля или вне текстуры — как раньше. Замер (Каянча, «Высокий», окно 1920×1080, среднее GPU-время кадра за 150 кадров,tools/shots/wind_field_shot.gd --gpu=150,flock /tmp/heat_ca_gpu.lock): с полем 9,09 мс (два прогона: 9,087 и 9,093), без поля 8,991 мс — Δ ≈ 0,10 мс (трава и рябь воды вместе, в бюджете ≤ 0,2 мс; замер по всему кадру окна — трава и вода в нём лишь часть общей стоимости).
Масштаб 2: термики из поля (AM-07)
Нынешняя модель термиков (thermal_field.gd, atmo_thermal.gd: пузыри, ядро Гедеона, радиус по
Аллену, рост/зрелость/распад, снос, облака над термиком) осталась; когда есть поле с входом
решения, из поля берутся место, сила, радиус, потолок и снос. Ядра — по модели восходящих потоков
Аллена (AM-07б): сколько их, какого радиуса и силы — от толщины слоя и w*; поле решает, где их
больше; восходящий поток поля сверх несомого ядрами — широкий слабый подъём в «между». Код: scripts/atmosphere/air_model/air_thermals.gd
(AirThermals — источники на час), thermal_field.gd (источники поля живут как клетки),
atmosphere.gd — одна строка (ThermalField.air). Тесты: tests/atmosphere/test_air_thermals.gd
(синтетика + фикстура Каянчи 12:00, tests/atmosphere/fixtures/air_model/thermals/). Замеры и
картинки: tools/research/air_thermals/ (README там).
Вход
Уровень — грубейший в AirFieldSet.levels (область места; общий у всех клиентов сети —
решение К0 Р10; окна 100/50 м вокруг пилота у каждого свои и для выбора источников не
используются). Кроме каналов (w_conv, θ′, u, v, рельеф сетки — WindField.raw_*, C4 v2) нужен
вход решения из meta (WindField.heat_flux/z_i/gam/u10): поток тепла H (ny·nx, Вт/м²), z_i (м
над морем), dθ̄/dz по уровням (К/м), U10 (м/с). Нет их — термики аналитические, как раньше.
Законы (для столбца поля; H_kin = H/(ρc_p), h = max(z_i − hc, 300 м), ζ = z/h)
| Что | Формула | Откуда |
|---|---|---|
| Масштаб скорости | w* = (g/θ0 · H_kin · h)^(1/3) (WindField.deardorff_wstar, одна функция с возмущениями AM-08; у ядра H — среднее по водосбору источника) | Дирдорф (1970), Stull (1988) гл. 4 |
| Избыток частицы | Δθ = b·H_kin/w_m, w_m = (u³ + 0,28 w³)^(1/3), b = 6,5 | Холтслаг–Бовилль (1993), то же замыкание, что у поля (air.py _closure) |
| Поток массы подсеточной конвекции | F(ζ) = H_kin(1 − ζ)/Δθ = w_m(1 − ζ)/b; по слою F̄ = w_m/(2b) | нелокальный нагрев поля H(1 − ζ) несут термики; M = w′θ′/Δθ |
| Восходящий поток поля | Φ = F̄ + max(W̄, 0), W̄ — средний w_conv слоя 0..h | подсеточный + организованный (схождение, склоны) |
| Потолок | частица θ̄ + θ′(у земли) + Δθ всплывает до θ̄ + θ′ поля; не выше кромки погоды | метод частицы; инверсия и тёплый слой θ′ гасят сами |
| Толщина слоя для ядер | z_l = потолок частицы − земля (без кромки), не меньше 300 м | местная толщина слоя перемешивания: утром над склоном она больше z_i − hc (z_i из прогноза ниже гребней) |
| Радиус ядра | r₂(ζ) = max(10 м, 0,102·ζ^(1/3)(1 − 0,25ζ)·z_l); у верха R = r₂(1) = 0,0765 z_l, ниже — тот же профиль термика | Аллен (2006, AIAA 2006-1510) по самолётным замерам Lenschow & Stephens (1980) |
| Живых ядер на площадь | n_A = 0,6/(z_l·r₂(½)) ≈ 8,5/z_l² (доля площади ядер ≈ 0,13) | Аллен (2006) |
| Сила | w0 = k·w*, k = e·max ζ^(1/3)(1 − 1,1ζ) = 1,24 | пик Гедеона с тем же потоком ядра, что средний подъём Аллена w̄ = wζ^(1/3)(1 − 1,1ζ) на уровне максимума (ζ ≈ 0,23); пик самого Аллена там ≈ 2,2 w̄ ≈ 1,0 w; ядра 1–2 w* — Lenschow & Stephens (1980), Young (1988) |
| Плотность источников | n = n_A·Φ/Φ̂ / p_жизни, но ≤ Φ/(w0·K̄); шаг укладки √(0,696/n), не ближе 2,5 R | Φ̂ — средний Φ кандидатов с весом n_A (итог по площади = Аллену), p_жизни — доля времени, когда термик источника жив (доля циклов × жизнь/период ≈ 0,71): живых — n_A; K̄ — средний по времени и столбу поток ядра одного пузыря на 1 м/с (форма, радиус Аллена, жизнь); ядра не несут больше Φ |
| Широкий подъём | организованный поток (W̄⁺) сверх несомого ядрами остаётся в w_conv − чистый поток пузырей | «между» (ниже); отдельной ручки нет — считается от поля |
| Снос и наклон | средний ветер поля по столбу источника (земля…потолок), постоянный на жизнь | WF-13 этап 1 |
| Кольцо опускания | множитель кольца Гедеона ρ = (1 − O/M)·e⁻¹/∫кольца | подсеточная доля потока ядра возвращается у пузыря (Гедеон ≈ 1,03, чистый ноль), организованная O (W̄⁺) уходит вверх |
| «Между» | w_conv(x, z) − ожидаемый чистый поток пузырей водосбора (по высоте — профиль ядра) | среднее (пузыри + между) = w_conv поля; фоновое опускание пресета в поле не действует |
Выбор источников: кандидаты — столбцы с H > 0, Φ > 0, столбом частицы ≥ 300 м (минимальная толщина слоя замыкания) и весом поля ≥ ½; по убыванию Φ, кандидат берётся, если в радиусе его плотности нет взятого. Водосбор — ближайшие столбцы (не дальше 2 радиусов): по нему w* (средний H) и доля организованного потока O/M (кольцо, «между»). Точка источника внутри столбца — лучшая по освещённости земли (скалы, опушки, как у клеток), сид — столбец и сид мира. Термик источника живёт как клетка: свой период и фаза, доля циклов, рост/зрелость/распад, облако, Cb и редкие очень сильные — из погоды, как было; радиус — Аллена (у очень сильных — не меньше пресета). Частица не дошла до кромки — облака нет.
AM-07б — что изменилось и почему. В AM-07 ядра с радиусом из пресета (90–170 м) несли весь Φ: сила = поток водосбора / поток одного пузыря (до 2,5 w*), источников — сколько нужно, чтобы унести Φ. Итог 12:00: 4,1 м/с, соседний живой 252 м, 9056 термиков за 4 ч. В слое конвекции восходящий поток несут не только когерентные ядра, которые обрабатывает пилот: доля площади подъёма 0,3–0,4 (Lenschow & Stephens 1980; Stull 1988 гл. 4), ядра — меньшая часть, остальное — широкий слабый подъём. Теперь число, радиус и сила ядер — от z_l и w* по Аллену (2006), а поле решает только, где ядер больше (∝ Φ). Ядра несут 37–45 % Φ днём, 12–21 % утром; остаток организованного потока — широкий подъём в «между» (поле), подсеточный остаток (F̄ сверх ядер) имеет чистый поток ноль и пилоту не выдаётся. Стык C4 не меняется (w_conv пилоту — только через пузыри + «между»), C5 — тоже (меняется лишь, какие столбцы в маске).
Стык с аналитикой: клетки сетки с источником там, где поле покрывает землю (вес ≥ ½), не
рождают; вне поля — аналитика как раньше. Поле выключено или нет входа — всё побитно прежнее
(тест test_atmosphere_field_region_and_off). Отпечаток детерминизма — с выключенным полем.
Числа (Онгудай, 3 м/с со 150°, ясно, типичный июль; эталон AM-01, make_fields.py)
Приёмка 1 — где термики (плотность источников, 1/км², по классам столбцов окна 100 м; AM-07б):
| Поле | Прогретые (верх. четверть H) | Слабо прогретые (ниж. четверть) | Схождение W̄ > 0,1 | Опускание W̄ < −0,05 | Тень H ≤ 0 |
|---|---|---|---|---|---|
| окно 100 м, 12:00 | 4,9 | 0,7 | 3,7 | 0 (56 столбцов) | — |
| окно 100 м, 15:00 | 3,2 | 1,5 | 2,6 | 0 (56) | — |
| окно 100 м, 9:00 | 10,6 | 3,6 | 14,8 | 8,6 | 0 (129 столбцов) |
Сила у всех источников одна доля w* (1,24): 12:00 — 2,7–3,2 м/с, 15:00 — 2,9–3,4, 9:00 — 1,1–1,5. Утром слой тонкий (z_l ~ 300–800 м) — ядра мелкие (R 25–60 м) и частые, как у Аллена; на области 400 м больше одного источника на столбец не бывает (≤ 6,25/км²).
Карты: tools/research/air_thermals/out/fig_sources_<поле>.png (H, W̄, Φ, источники ∝ силе
поверх рельефа); было/стало — fig_before_after_kayancha_w100_h12.png,
fig_before_after_ongudai_d400_h12.png. Синтетика (тест): в тени (H < 0) источников 0, на оси
схождения источник ±150 м, в схождении источники в 2,4 раза гуще (8,7 против 3,6/км²).
Приёмка 2 — потолок: инверсия 20 К/км над z_i = 2000 м → потолок частицы 2061 м; 5,8 К/км → 2212 м (проскок Δθ/Γ); тёплый слой θ′ +2 К на 800 м → 1808 м (≈ 800 м над землёй); в атмосфере термики — до инверсии, а не до кромки 2600 м, без облака; частица выше кромки — до кромки. Реальный рельеф 9:00 (утренняя крышка): столб 575 м (p10–p90 350–830), 12:00 — 1440 м (до кромки), 15:00 — 1640 м.
Приёмка 3 — поток массы (окно 100 м 12:00, Монте-Карло 60 мин, flux.json; AM-07б):
| ξ | ядра (w > 0) | ожидание ядер | кольца (w < 0) | «между» + (широкий подъём) | «между» − | итого пилоту | w_conv поля |
|---|---|---|---|---|---|---|---|
| 0,25 | 0,079 | 0,088 (0,90) | −0,039 | 0,132 | −0,016 | 0,156 | 0,173 (−10 %) |
| 0,5 | 0,101 | 0,121 (0,83) | −0,050 | 0,083 | −0,001 | 0,133 | 0,157 (−15 %) |
| 0,75 | 0,111 | 0,137 (0,81) | −0,055 | 0,060 | 0,000 | 0,116 | 0,141 (−18 %) |
м/с, среднее по площади внутри окна. Ядра / ожидание < 1 — часть потока сносит ветром за край окна (по термикам без пространства — 0,93); итог в пределах ±20 % от поля, как в AM-07. Ядра несут 37 % Φ (окно 12:00), 38 % (15:00), 21 % (9:00); область 400 м — 42/45/12 %. Синтетика в штиль (тест): ядра / ожидание 0,95.
Приёмка 5 — сила, радиус, густота против литературы и базы AM-00 (круг 6 км у Каянчи на области
400 м, круг 2,5 км на окне 100 м; 4 ч; stats.json; база — аналитика в тот же день, та же кромка):
| сила ядра, м/с (ср.; p10–p90) | R у верха, м | потолок над землёй, м | живых на км² | соседний живой, м | термиков за 4 ч | |
|---|---|---|---|---|---|---|
| поле 12:00 (область 400 м) | 2,96 (2,70–3,21) | 161 (137–195) | 1305 | 2,3 | 394 | 3792 |
| поле 12:00 (окно 100 м) | 2,94 (2,65–3,18) | 156 (135–176) | 1201 | 2,7 | 435 | 768 (круг 2,5 км) |
| поле 15:00 | 3,15 (2,89–3,40) | 187 (160–219) | 1538 | 1,9 | 462 | 3050 |
| поле 9:00 | 1,35 (1,13–1,52) | 44 (медиана; 28–148*) | 551 | 2,7 | 318 | 4302 |
| AM-07 12:00 (было) | 4,1 (2,4–5,9) | 90–170 (пресет) | 1375 | ~5 (оценка) | 252 | 9056 |
| аналитика / база AM-00 | 2,35 (1,1–3,4) | 104–149 | 990–1620 | 0,7 | 650–660 (586–603) | ~1100 (13 488 на круг 20 км) |
| Аллен (2006) | w̄ ≤ 0,46 w*, пик ≈ 1,0 w* (≈ 2,3 м/с при w* 2,3) | 0,0765 z_l: 150–190 при z_l 2–2,5 км | z_i | 8,5/z_l²: 1,4–2,1 днём, ~26 утром | Пуассон 0,5/√n: 350–420 | |
| литература | ядра 1–2 w* (Lenschow & Stephens 1980; Young 1988) | — | между сильными — 1–1,5 z_i (≈ 2–3 км; ячейки конвекции, Stull 1988) |
* 9:00 — p90 с термиками аналитики у края круга. Густота теперь по Аллену (живых 1,9–2,7/км² против 8,5/z_l² ≈ 1,4–2,1: чуть выше из-за Φ/Φ̂ — Каянча на прогретом склоне), вдвое реже AM-07, в 2,5–3 раза гуще аналитики. Расстояние 1–1,5 z_i — это масштаб ячеек (сильных термиков), а Аллен считает все ядра, поэтому соседний живой ~0,2 z_l, а не 1–1,5 z_i; разброс силы у ядер теперь узкий (только от w* водосбора), в жизни — шире. Утром (9:00) Аллен даёт ~26/км² мелких ядер; область 400 м держит не больше одного источника на столбец, и Φ-ограничение (ядра не несут больше Φ) — отсюда 2,7/км².
Сеть
Поле у клиентов чуть разное (своя видеокарта), выбор источников — нет: ведущий шлёт
ZoneState.thermal_sources (net.proto, C5): подпись сетки уровня "dx,x0,y0,nx,ny" и битовую
маску столбцов-источников (бит j·nx + i, base64; область 96 × 96 — 1,5 КБ в каждом ZoneState,
1 Гц). Остальные ставят маску своей атмосфере (ThermalField.set_air_forced, NetFlight. sync_thermal_sources) и считают силу, потолок и снос по своему полю. Новый ведущий переходит на
свой выбор. Замер (шум поля 1e-3·|u₀| = 5,4 мм/с, net.json): без ведущего окно 100 м расходится
в 24 из 103 столбцов (12:00), 23/85 (15:00), 26/362 (9:00); область 400 м — 46/2860 (12:00),
37/3993 (9:00) (AM-07б; в AM-07 область почти сплошь была источниками — 0/8463).
С маской ведущего (тест, шум 3e-3): те же термики, |Δсила| ≤ 0,008 м/с, |Δось| ≤ 0,4 м, |Δпотолок|
≤ 0,3 м. Квантование без протокола не взято: на окне оно не спасает, а на области нужно для
редких пороговых столбцов.
Чего не умеет
- Сила ядра — одна доля w* (Аллен), без разброса у соседних ядер; в жизни сила ядер распределена шире (Lenschow & Stephens 1980). Ширина ячеек (сильные термики через 1–1,5 z_i) не моделируется: ядра Аллена — все восходящие потоки.
- Геометрия ядер — по z_l (частица), w* — по h = z_i − hc (общая функция с AM-08); утром над гребнями z_l > h.
- Тень облаков на источники поля не действует: облачность неба уже в H поля (sky.heat), а тень каждого облака без поправки поля вдвое уменьшала поток пузырей (замер 0,48 против 0,98).
- Улицы (выстраивание по ветру) у источников поля нет: среднее поле валов не даёт.
- Список источников — на час поля (пересчёт поля — новый список, живые доживают); вход в поле по ходу дня (инсоляция, перистые) до пересчёта не влияет.
- Мелкие утренние термики со столбом < 300 м не рождаются (порог толщины слоя замыкания).
- Сборка источников — главный поток: окно 64 × 64 ~0,13 с, область 96 × 96 ~0,55 с + точки источников по освещённости (~2–4 с на область с рельефом) — раз на поле; в рабочий поток — AM-11.
Границы модели: разрешение сетки и перенос
Среднее поле считается с переносом 1-го порядка на клипмапах 400 м (область) и 100/50 м (окна вокруг пилота), без окна 25 м и без поправок.
- Разгон у бровки занижен на 15–20 % на высотах 20–100 м над склоном. Над стартом Каянча при встречном на старте ветре (нейтрально, 6 м/с) скорость при клетке 50 м и 1-м порядке составляет 0,80 / 0,83 / 0,84 / 0,92 от решения с клеткой 25 м и 2-м порядком на 20 / 30 / 50 / 100 м.
- Причина — численная диффузия переноса 1-го порядка и разрешение рельефа клеткой: ошибка растёт на крутых и узких склонах и убывает с размером клетки. При клетке 12,5 м и 2-м порядке решение сходится к независимому линейному эталону (потенциальное обтекание + поправка на сдвиг среднего слоя) и к измерениям на холме Askervein (разгон на вершине на 10 м: 0,61 против измеренных 0,82; линейный эталон — 0,78).
- 2-й порядок переноса не включён: на крутом рельефе у него нет установившегося решения (Аньези H = L), а на реальном рельефе он сходится в 2–3 раза дольше.
- Путь исправления, если пилоты скажут «на бровке слабо»: 2-й порядок в окнах 100/50 м (время ×2–3) или окно 25 м. Калибровка параметров под это не подкручивается.
- Числа и воспроизведение —
tools/research/air3d/reference.md→ «4. Askervein»,out/ref/askervein*.json.
Калибровка (AM-09)
Параметры подогнаны по количественным данным (Askervein, подобие конвективного слоя, закон −5/3) по схеме Professor. Подробно — docs/research/air-model-tune.md. Изменился один параметр — длина перемешивания у рельефа: λ = max(40 м, 0,25·h) вместо 0,1·h. Это верхняя граница физичного диапазона, данные тянут выше. Слова пилота в подгонку не входили. Ниже — сравнение с ними после калибровки; модель и коэффициенты по этому сравнению не исправлялись.
Слова пилота против модели после калибровки
Синтетика эталона (tools/research/tune/pilot_check.py, как synth.py AM-01), ветер 5 м/с (на высоте 9 м/с); провалы — точка базы AM-00, 20 км/ч, turb_probe.gd --only=lee на полях с параметрами калибровки.
| Слова пилота | Цель | Модель (AM-09) | До калибровки (AM-01/AM-08) | Совпадает? |
|---|---|---|---|---|
| полоса подъёма ≈ 2 H, выше — спокойно: разгон над хребтом H = L = 500 м на 2 H / 2,5 H над подножием | ≤ 10 % / ≤ 5 % | 19 % / 16 % (потенциальное обтекание — 24 % / 16 %) | 19 % / 17 % | нет |
| седловина ×1,5: скорость на 20 / 50 м над седлом к подходу | 1,5 ± 0,2 | 1,90 / 1,74 (ветер по оси); 1,84 / 1,69 (15°) | 1,91 / 1,76; 1,84 / 1,70 | нет (на 50 м — на границе) |
| в седловине ветер поворачивает к её оси (ветер 15°) | ≤ 5° | 4,2° | 4,1° | да |
| косой ветер 45° — подъём слабее: w(45°)/w(0°) | 0,55–0,8 | 0,72 (50, 100, 200 м) | 0,72 | да |
| провалы за гребнем как в игре до поля: σ_w и частота рывков против базы AM-00 (Синюха / Бияготы / Аушкуль) | ±20 % | σ_w +81 / +90 / +30 %; рывков −17 / −14 / −71 % | +80 / +90 / +18 %; −17 / −14 / −70 % | нет |
Границы модели: калибровка (AM-09)
- Седловина ×2,05 вместо ×1,5 (×1,9 до А1: выхолаживание с τ гасило и адиабатическое охлаждение поднятого воздуха, см. ниже). При числе Фруда около 2 поток переваливает через весь хребет, и седловина в модели работает не как «труба», а как понижение гребня: у земли над седлом ветер в 2,05 раза сильнее подхода (на 50 м — в 1,87) и слабее, чем над соседней вершиной. Полевое ×1,4–1,6 (Gebbies Pass) и ×1,5 пилота получены, вероятно, при другой устойчивости и геометрии. Устойчивость дня и так приходит из погоды, отдельной «ручки седловины» нет, и подгонять её не стали.
- Полоса подъёма выше 2 H над крутым хребтом (H = L). На 2 H разгон ещё около 19 %. Потенциальное обтекание того же рельефа даёт 24 %, так что расхождение со словами «≈ 2 H» — свойство крутой геометрии, а не ошибка решателя.
- Провалы за гребнем — по физике, не по базе (AM-08в, решение пользователя: приёмка σ_w = 0,14·ΔU слоя смешения и обратный поток по Menke 2019, сравнение с базой AM-00 — наблюдение). До AM-08в σ_w в подветренной точке была на 30–90 % больше базы (ΔU от наибольшего ветра столба 600 м, рывки 1,0·ΔU); после — на 25–65 % меньше (ΔU от ветра на уровне гребня, рывки — часть σ_w). Разбор — «Масштаб 3 → Числа».
- Разгон у гребня и сразу за вершиной занижен даже на мелкой сетке. На холме Askervein при клетке 12,5 м и 2-м порядке модель даёт у вершины на 10 м 0,59 против 0,88 измеренных (в пределах погрешности сетки 0,17), вдоль гребня — на 0,1–0,3 меньше. Сразу за вершиной модель уже тормозит поток (0,19 против 0,68 и −0,07 против 0,40), а в измерениях там ещё разгон. Данные тянут длину перемешивания за физичную границу (λ/h до 0,6). Причины — K-замыкание первого порядка, стационарное среднее поле и неразрешённый внутренний слой. Подкручивать калибровкой нельзя; путь тот же, что для бровки: 2-й порядок и окно 25 м.
- Болтанка над вершиной и на наветренном склоне завышена. Масштаб 3 считает σ по местной скорости трения, и над разогнанной вершиной ТКЭ растёт в 1,5–4 раза. На Askervein измеренная ТКЭ там почти как на равнине: турбулентность не успевает за разгоном среднего ветра (быстрое искажение, Britter, Hunt & Richards 1981). За гребнем модель совпадает с измерениями в пределах погрешности. После AM-09б (одна длина перемешивания у масштаба 3 и решателя) χ² ТКЭ Askervein 141 → 33, но вершина остаётся завышенной (χ² 10,3 на 4 мачты): быстрого искажения в модели нет, параметром это не исправить. Решение 30.09.2026: оставить границей модели; структурную правку — только если пилот скажет, что над вершиной болтает слишком сильно.
- За гребнем Синюхи σ_u на 100 м выросла на 52 % при λ/h 0,1 → 0,25 (400 м за гребнем, 2,06 → 3,13 м/с; остальные точки таблицы σ — не больше 4 %). Точка в слое смешения за отрывом, где более длинная длина перемешивания ожидаемо усиливает болтанку. Не подгоняется; проверяется полётом пилота (AM-12).
- λ/h = 0,25 — временно, до перекалибровки (заменено совместной калибровкой Б1: 0,0158 с полом 40 м, α по устойчивости — см. «Границы модели: профиль притока и длина перемешивания (Б2)»). Вывод AM-09 «данные Askervein тянут λ/h выше» оказался следствием показателя профиля притока α, выбранного вручную (0,17): по профилю опорной мачты RS в данных α ≈ 0,22, и при α 0,20–0,24 χ² падает с 86 до ~54, а λ/h уходит к нижнему краю (docs/research/air-model-sensitivity.md, отбор Морриса 01.10.2026). Askervein определяет по сути одну комбинацию λ/h, α, порядка переноса, local_k, λ (94 % действия — одно направление SVD). Значение пересматривается перекалибровкой по (λ/h, α, z0) с профилем RS в наблюдаемых.
- Турбулентное число Прандтля Pr_t = 0,85 — постоянное (K_θ = K/Pr_t, один множитель на вертикальную и горизонтальную диффузию тепла; Kays 1994, середина измерений нейтрального слоя 0,74–0,95). Значение выбрано пользователем 30.09.2026 из вариантов 1,0 / 0,74 / 0,85 / 0,95. Зависимости от устойчивости Pr_t(Ri) нет: измерения дают 0,5–0,7 у земли в конвекцию и > 1 при Ri ≳ 0,2 (Li 2019); устойчивость в модели уже в F(Ri) местного K, конвективный перенос — нелокальный источник по слою перемешивания. Влияние на подъём мало (Онгудай 12:00, окно 50 м, Pr_t 1,0 → 0,85): при 3 м/с −0,003 м/с, в штиль −0,035 м/с (0,44 → 0,41).
- Выхолаживание с τ = 2 ч действует только на диабатическую часть θ′ (от нагрева Q; второй переносимый скаляр θ′_d, А1). Адиабатические θ′ устойчивого обтекания (поднятый воздух холоднее фона на γ·δz) сохраняются и исчезают только перемешиванием — как в физике на масштабе области (радиационное выхолаживание — сутки). τ заменяет то, что средний прогрев слоя за день уже в фоне θ̄(z) погоды; физичнее источник Q − ⟨Q⟩ без τ — другая постановка, не сделано. Следствия (физика модели, не подгоняются): седловина без нагрева от τ не зависит (×2,06 при τ 1800 и 21600 с; до А1 ×1,71 и ×1,99); в штиль подъём у старта ниже — Онгудай 12:00, окно 50 м 0,52 → 0,44 м/с (−15 %, при Pr_t = 1; с Pr_t = 0,85 — 0,41): термики над склоном перехлёстывают верх слоя перемешивания и в устойчивом слое над z_i остывают адиабатически, раньше τ за 2 ч стирал это охлаждение и крышка слоя «протекала»; при 3 м/с разницы нет (1,33 м/с).
- В штиль сходится дольше, местами не сходится. Без стока 1/τ у полного θ′ область 400 м в штиль 12:00 — 161 итерация вместо 61 (≈ 2 с на 4070 SUPER), без нагрева при ветре +50 % итераций; область 200 м, 3 м/с с нагревом — не сошлась за 3000 итераций (эталон air.py). В штиль и раньше часто не сходилось (окно 50 м, 12:00: 139 из 205 точек Морриса). Это задача сходимости (А2), не откат правки.
- Шаг сильных термиков (1–1,5 z_i) модель не воспроизводит по построению. Все ядра одной силы (доля w*), порога «сильный» нет. Густота всех ядер совпадает с литературой: N·z_i/L = 1,4–1,5 против 1,2 ± 0,4 (Lenschow & Stephens 1980).
- Не определены данными и оставлены прежними: пороги признака отрыва масштаба 3, поток тепла с луга H0 = 330 Вт/м², время выхолаживания τ диабатической θ′_d.
Границы модели: профиль притока и длина перемешивания (Б2)
Профиль ветра по высоте — одна функция у решателя (ветер на границах области и окон) и у аналитического ветра
(scripts/atmosphere/wind_profile.gd, эталон tools/research/air3d/wind_prof.py, контракт C2 v4). Подробно и числа —
docs/archive/plan/air-model-b2.md.
- α — по устойчивости, а не по местной шероховатости. U(z) = U10·(z/10)^α до z_sat, выше — постоянный. α = 0,24 · r(класс): класс Паскуилла–Тёрнера по таблице Тёрнера (1964; ветер на 10 м и индекс радиации — высота солнца и облачность днём, облачность ночью), r — отношение показателя класса к нейтральному D по Irwin (1979, сельская местность): A, B 0,47; C 0,67; D 1; E 2,33; F 3,67. Полдень, ясно: штиль и 3 м/с — A/B, α 0,11; 6 м/с — D, α 0,24. Облачно — на класс-два ближе к D. Местный z0 в α не входит: зависимость α от z0 (Counihan) с калибровкой не согласуется (Askervein z0 0,05 → α 0,14 по формуле против 0,24 по данным).
- α_N = 0,24 — эффективный показатель до z_sat, а не лог-профиль. У земли лог-профиль с z0 0,1 м дал бы ≈ 0,15–0,16; 0,24 — совместная калибровка Askervein (α 0,242 ± 0,004) с насыщением z_sat ≈ 450 м. Perdigão над лесом упирается в край сетки (≥ 0,29) — лес в игре не учтён.
- z_sat = 0,3·h, h = 0,3 u/f* — толщина нейтрального слоя модели: 3 м/с — 208 м, 6 м/с — 415 м. Проверено профилями притока (змей Askervein до 267 м — насыщения нет; лидары Perdigão — рост прекращается на 420–590 м). Для устойчивых E, F (вечер после ≈ 20:25) h = min(0,3 u*/f, 0,4 √(u*·L/f)), L по классу и z0 — Golder 1972 (C2 v5): при 3 м/с z_sat 39 м (E) и 22 м (F), на высоте ≈ 2 × U10, как в нейтраль; сдвиг — в нижних десятках метров. Ночной струйный максимум (ветер над слоем больше геострофического) модель не воспроизводит. Данными притока устойчивые случаи не проверены (калибровка — нейтральная).
- Облачность в классе устойчивости — доля неба из прогноза (ясно 0, переменная 0,3, облачно 0,85); кромки облаков в классе нет — взята ветка Тёрнера «нижняя граница ниже 7000 футов» (облачно — инсоляция на 2 ступени ниже). Перистая пелена класс не меняет.
- «Ночь» Тёрнера (час до заката — час после восхода) — солнце ниже 8°: подобрано по Онгудаю в июле (час после восхода ≈ 9°, до заката ≈ 7°); на других широтах и в другие сезоны граница сдвинута на минуты–десятки минут.
- λ = max(40 м, 0,0158·h) — совместная калибровка Б1: общий λ ≈ 27 м; одним λ модель не может одновременно
усилить рециркуляцию в долине за двумя грядами (Perdigão тянет λ вниз) и ослабить след за одиночным холмом
(подветренная сторона Askervein тянет вверх) — напряжение структурное, не параметрическое. Пол 40 м — граница
устойчивости сходимости (lam 27 м не сходит окно 100 м в штиль). Та же λ у масштаба 3 (
FieldTurbulence): выше ≈ 100 м над землёй длина перемешивания болтанки от сдвига теперь 40 м вместо 0,25·h. ТКЭ Askervein (метод AM-09б) с новой λ: модель по-прежнему завышает ТКЭ на наветренном склоне и вершине в 2–3 раза; χ² с одной σ данных 4297 → 3889, с σ сетки 33 → 255 — поля 12,5 и 25 м стали ближе, и завышение больше не покрывается погрешностью сетки (docs/archive/plan/air-model-b2.md).
Масштаб 3: возмущения из поля (AM-08)
Нынешние болтанка, рывки, подветренная эвристика и ротор остаются формой; где есть поле
(доля a > 0), сила и масштабы берутся из поля масштабов 1–2 по физике пограничного слоя. Без поля,
вне поля и при air_model.enabled = off — побитно прежняя аналитика
(tools/bench/air_velocity_bench.gd --compare: 38 400 значений, 0 отличий; база AM-00 в
подветренных точках повторяется до знака). Код: Atmosphere._air_velocity_field,
scripts/atmosphere/field_turbulence.gd (FieldTurbulence: признак отрыва, σ, рывки); величины поля — WindField.turb_at / AirFieldSet.sample_turb
(контракт C4 v3); шум — scripts/atmosphere/gust_spectrum.gd. Коэффициенты —
configs/atmosphere.json → turbulence.field_*, lee.field_* (у каждого _doc с источником).
Замеры — tools/research/air_turb/ (README там).
Что берётся из поля (по столбцам и в точке)
- u* = κ|U_r|/ln(a_r/z0) — лог-закон по первой воздушной клетке с центром не ниже dz/2 над рельефом сетки (клетка ниже сидит в «углу» ступеньки маски и тормозится лобовым сопротивлением: u* по ней занижен вдвое — видно на стартах Синюхи и Бияготы); z0 = 0,1 м решателя.
- Сдвиг |∂U_h/∂z| на высоте точки (производная линейной интерполяции между клетками, ниже
первой клетки — производная лог-профиля) и N² = g/θ0·(dθ̄/dz + ∂θ′/∂z) (фон
meta.gam+ θ′ поля). - «Внешний» ветер U_out — наибольшая |U_h| столбца в 600 м над рельефом, и наклон опускания s_d = −min w_mech/U_out в том же слое.
- w* Дирдорфа по потоку тепла H (сглажен квадратом 1500 м, как
Params.k_smooth_m) и h = max(z_i − hc, 300 м) —WindField.deardorff_wstar, та же формула, что у термиков AM-07. Сверка (wstar_check.gd, w* болтанки в точке источника / w* источника): Каянча 12:00 — 1,001 ± 0,038 (54 источника), Синюха — 1,000 ± 0,021 (213), Аушкуль — 1,000 ± 0,010 (196); разница — только в осреднении H (квадрат 1500 м против водосбора источника), до ±9 % в отдельных точках.
Законы
- Механическая болтанка: u*_m = max(u*·(1 − z/h)^¾, l·|∂U/∂z|), l = 1/(1/κz + 1/λ), λ = max(40 м, 0,25·h) (Прандтль–Блэкадар, то же замыкание, что у решателя, AM-09б; (1 − z/h)^¾ — Nieuwstadt 1984; h — слой перемешивания поля или нейтральный 0,3 u*/f, как у решателя; λ/h и 0,3 — константы AirCase). В приземном слое (ниже 0,05–0,1 h, Stull 1988, §1.5; переход smoothstep) u* стенки заменён u* в точке κ·U(z)/ln(z/z0) по среднему ветру поля, который получает пилот (AS-2: u* столбца берётся по клетке выше и на стартах расходился с ветром в точке на −12…+22 %). σ_w = 1,25 u*_m (Panofsky & Dutton 1984), σ_u = σ_w·(0,177 + 0,000823 h_ft)^(−0,4) (анизотропия MIL-HDBK-1797: 2 у земли → 1 к 300 м, т. е. σ_u ≈ 2,5 u* у земли), σ_v (поперёк ветра) = σ_w·(1 + 0,56·(σ_u/σ_w − 1)) — у земли 1,9 u* (σ_u : σ_v : σ_w = 2,4 : 1,9 : 1,25, Panofsky & Dutton 1984; Kaimal & Finnigan 1994, §1.6), выше — к изотропии вместе с σ_u (до AS-2 σ_v = σ_u: разброс направления на 25 % больше). Пульсации горизонтали кладутся вдоль и поперёк среднего ветра в точке. Рост у рельефа — сам: на бровке разгон поднимает u*, за гребнем — сдвиг оторвавшегося слоя.
- Устойчивость (Монин–Обухов просто): градиентное Ri = N²/S²; u*_m делится на (1 + 5Ri) — корень функции устойчивости замыкания решателя F = 1/(1 + 5Ri)² (K ∝ l²S·F, u*_местн = √(K·S)). При Ri < 0 поправки нет — неустойчивость даёт конвективная часть. Масштабы вихрей не больше σ_w/N (Hunt, Kaimal & Gaynor 1985): L = 1/(1/L_MIL + N/σ_w).
- Конвективная: σ_w = w*·√1,8·ξ^⅓(1 − 0,8ξ), ξ = z/h (Lenschow et al. 1980), σ_u = σ_v = 0,6 w*; шум несёт только вертикаль мельче конвективных вихрей: × (L_w/0,22h)^⅓ (пик спектра w на 1,5 z_i — Kaimal et al. 1976; крупнее — термики AM-07 и поле). H ≤ 0 — конвекции нет; нет данных о нагреве в поле — прежняя аналитика по погоде.
- Сложение механики и конвекции (AS-2) — как в подобии приземного слоя: σ³ = σ_m³ + σ_c³ для каждой компоненты: σ_u/u* = (12 + 0,5 z_i/|L|)^⅓, σ_w/u* = 1,25(1 + 3|z/L|)^⅓ (Panofsky et al. 1977; 0,5 z_i/|L| = 0,5κ(w*/u*)³, т. е. σ_u,c → 0,59 w*, σ_w,c → 1,34 w*(z/z_i)^⅓ — тот же Lenschow у земли). До AS-2 — сумма квадратов: в смешанном режиме (u* ≈ 0,6, w* ≈ 2,2 м/с у стартов в полдень) σ_u на 20–30 % выше подобия.
- Масштаб конвективной горизонтали (AS-2): дисперсия горизонтали сверх механической (доля 1 − σ_m²/σ²) несётся вихрями масштаба слоя L = 0,22 z_i (пик спектров u, v на ~1,5 z_i, Kaimal et al. 1976; фон Карман — пик k·S на 6,87 L), а не высоты над землёй: у земли это медленные «циклы» ветра (L/U ≈ 1–2 мин), не порывы за секунды. До AS-2 вся σ_u = 0,6 w* шла с L_u(z) ≈ 23 м — на 1,5 м над стартом при 3 м/с ветер разворачивался на 180° за несколько секунд.
- Перенос вихрей у земли (AS-2): шум один на всю атмосферу и переносится ветром 300 м (advect; местный перенос рвал бы шум сдвигом по высоте), а вихри приземного слоя несёт местный ветер U(z) (гипотеза Тейлора с местной скоростью переноса — Willis & Deardorff 1976; Kaimal & Finnigan 1994, §2.5). У стоящего пилота время вихря — L/U, а шум давал L/advect: при 6 м/с у земли advect/U ≈ 3–4. Масштабы механических вихрей растянуты в r = advect/U раз (1 ≤ r ≤ 8) с весом e^(−agl/10 м): ниже ~размаха крыла пилот стоит, бежит или выравнивает; выше он летит ~10 м/с относительно воздуха, и встречу с вихрями задаёт полёт (там растяжение исказило бы частоту при полёте по ветру и поперёк).
- За гребнем: признак отрыва lee_f = smoothstep(0,3; 0,7; ex)·smoothstep(0; 0,05; s_d),
ex = 1 − (|U|/U_out)/(ln(z/z0)/ln(a_out/z0)) — дефицит скорости против лог-профиля под внешним
ветром (прилегающий поток на подветренном склоне Askervein — до ΔS ≈ −0,3…−0,4, в следе и
пузыре ex → 1); опускание отличает след от торможения у наветренного подножия. Вместо линии тени
12° (она осталась для аналитики и для доли 1 − a у края поля). В зоне (C4 v4, AM-08в):
- скачок слоя смешения ΔU = max(U_H − |U|, 0)·lee_f, U_H — |U_h| поля в той же вертикали на
уровне гребня, высота земля + max(r, agl) (r — превышение гребня против ветра,
GroundField.relief_at): слой смешения отделяет поток над гребнем от следа, и скачок через него — от ветра на уровне гребня, а не от наибольшего ветра столба 600 м (U_out ≈ 2 U_H при 9 м/с у земли: ветер выше гребня разогнан и усилен с высотой); - болтанка слоя смешения σ_u = 0,18 ΔU, σ_w = 0,14 ΔU (Bell & Mehta 1990; Pope 2000, §5.4) — берётся большее из неё и механической;
- рывки вниз — часть этой болтанки, не среднего потока: прежние пятна шума (burst_*), амплитуда 0,42·ΔU·опасность = пик 3σ_w слоя смешения, с нулевым средним (вычитается среднее g по распределению шума — поток массы уже в w_mech) и только при включённой болтанке; их доля дисперсии вычитается из гауссовой части, так что полная σ_w в зоне = 0,14 ΔU (с выключенной болтанкой w в зоне — ровно w поля);
- обратный поток у земли 0,22·U_H·lee_f·опасность·e^(−agl/0,4r)·(1 − res) — максимум
обратной скорости в пузыре отрыва / U100 = 0,22 ± 0,08 (Perdigão, нейтраль, Menke et al. 2019);
res = smoothstep(4, 8, L/dx), L = 2,8 r — длина пузыря (Menke 2019: L/H ≈ 2,8), dx — клетка
поля в точке (
AirFieldSet.sample_dx). Эвристика только там, где пузырь решателем не разрешён: замер AM-08в (ниже, «Числа → Пузырь отрыва») — поле само течёт назад у ~30 % точек зоны при L/dx ≥ 8, у 15 % при 4–8 и почти никогда (0–3 %) при L/dx < 4. В окнах 50/100 м за гребнями выше ~70/140 м пузырь даёт поле, на области 400 м — эвристика; - масштаб вихрей ≥ 0,5 × превышение гребня (слой смешения не прижат к земле, Castro & Haque 1987).
- скачок слоя смешения ΔU = max(U_H − |U|, 0)·lee_f, U_H — |U_h| поля в той же вертикали на
уровне гребня, высота земля + max(r, agl) (r — превышение гребня против ветра,
- Двойной счёт снят: с полем w_mech не умножается на (1 − lee), эвристическое опускание и ослабление ветра за гребнем не добавляются (только в аналитической доле у края поля).
- Спектр: порывы — сумма 8 октав симплекс-шума (масштабы 8…1024 м; одна октава — полоса с
пиком k·S на 1,75 масштаба,
noise_line.gd), вес октавы — дисперсия спектра фон Кармана в её полосе (продольный — для u, v; поперечный — для w), L по MIL-HDBK-1797 (ниже 1000 футов L_w = h, L_u = h/(0,177 + 0,000823h)^1,2; от 2000 футов 2500 футов), нормировано на СКО 1. Прежний двухмасштабный шум (45 и 300 м, по 2 октавы с весом ½) в инерционном интервале падает как f^(−2,9) и круче f^(−5) выше 0,5 Гц — противоречит −5/3, поэтому с полем заменён.
Числа
У старта, 1,5 м над землёй (AS-2; tools/research/air_start/as2/, сцена игры с полем GPU, ветер
меню встречный, 12:00, ясно; σ модели — в точке, теория — подобие для u* в точке и z/L по w*, z_i поля:
σ_w = 1,25u*(1 + 3|z/L|)^⅓, σ_u = u*(12 + 0,5z_i/|L|)^⅓, σ_v = u*(1,9³ + 0,5z_i/|L|)^⅓; max|θ| —
наибольшее отклонение направления от среднего за 20 с, max|ΔU| — изменение модуля за 0,5 с, по
сидам 0/1500/3000; до AS-1 ветер над стартом в 1,0–1,8 раза больше меню):
| старт | меню | U10 / Ū(1,5 м) поля | u* в точке | z/L | σ_w до→после / теор. | σ_u до→после / теор. | σ_v до→после / теор. | max|θ| до→после | max|ΔU| до→после | w̄ поля / U·∇h |
|---|---|---|---|---|---|---|---|---|---|---|
| Каянча | 3 м/с | 3,2 / 2,2 | 0,29 | −0,27 | 0,40→0,36 / 0,44 | 1,54→1,40 / 1,35 | 1,54→1,36 / 1,33 | 178°→30° | 1,00→0,63 | 0,23 / 0,69 |
| Каянча | 6 м/с | 7,2 / 4,9 | 0,64 | −0,025 | 0,87→0,80 / 0,82 | 2,17→1,84 / 1,74 | 2,17→1,62 / 1,58 | 86°→31° | 3,98→2,14 | 0,59 / 1,53 |
| Синюха | 3 м/с | 4,7 / 3,9 | 0,43 | −0,12 | 0,48→0,54 / 0,60 | 1,52→1,44 / 1,38 | 1,52→1,33 / 1,30 | 47°→31° | 1,19→0,97 | 0,07 / 1,04 |
| Синюха | 6 м/с | 10,7 / 8,8 | 0,98 | −0,010 | 1,07→1,22 / 1,23 | 2,42→2,49 / 2,34 | 2,42→2,04 / 2,00 | 45°→44° | 4,21→4,15 | 0,21 / 2,33 |
| Биягода | 3 м/с | 3,0 / 1,9 | 0,26 | −0,27 | 0,40→0,33 / 0,40 | 1,62→1,46 / 1,42 | 1,62→1,44 / 1,41 | 180°→103° | 1,83→0,87 | 0,22 / 0,69 |
| Биягода | 6 м/с | 6,7 / 4,2 | 0,58 | −0,025 | 0,88→0,72 / 0,74 | 2,25→1,79 / 1,71 | 2,25→1,62 / 1,58 | 66°→38° | 4,52→2,16 | 0,72 / 1,52 |
| Аушкуль | 3 м/с | 3,5 / 2,3 | 0,31 | −0,19 | 0,42→0,41 / 0,45 | 1,66→1,52 / 1,46 | 1,66→1,48 / 1,44 | 142°→71° | 1,43→1,08 | 0,13 / 0,83 |
| Аушкуль | 6 м/с | 8,5 / 5,7 | 0,75 | −0,014 | 1,03→0,99 / 0,95 | 2,48→2,19 / 1,98 | 2,48→1,88 / 1,78 | 54°→48° | 4,89→3,06 | 0,45 / 2,01 |
Признак отрыва на всех наветренных стартах 0 (эвристика обратного потока и слой смешения ни при чём); σ_w у земли ≈ 1,25 u* — это подобие, не ошибка (аналитика гасит вертикаль у земли × agl/60 м и даёт 0,02–0,04). Скачок CF-1 на 4e71747 (окна 100/50 м) — старт попал в мелкое поле с этой σ_w и с наклоном потока вдоль склона (w̄ поля); рывки и развороты давали σ_v = σ_u, сумма квадратов механики и конвекции, конвективная горизонталь с масштабом высоты (L_u ≈ 23 м вместо 0,22 z_i) и перенос шума ветром 300 м (у земли в 2–4 раза быстрее местного: ветер 300 м аналитики с профилем по устойчивости — 4,2 м/с при 3 м/с и 13,6 м/с при 6 м/с меню). При 3 м/с остаётся медленный конвективный «цикл» (σ_u ≈ 0,6 w* при Ū ≈ 2 м/с): Биягода, сид 1500 — 20-с среднее 0,8 м/с, отклонение до 103°; теория даёт σθ ≈ σ_v/Ū ≈ 35–45°.
На ровном (синтетическое поле, лог-профиль, sl_table.gd, 600 с в точке): 6 м/с нейтраль, 1,5 м —
σ_u/σ_v/σ_w 1,31/1,22/0,64 → 1,30/0,90/0,62 (теория 1,25/0,99/0,65), время корреляции u 2,7 → 6,3 с,
max|ΔU| за 0,5 с (медиана по 20-с окнам) 2,22 → 1,50; на 50–300 м нейтраль — без изменений, кроме σ_v
(50 м: 0,88 → 0,76); конвекция H = 300 Вт/м², z_i = 1500 м: 100 м — σ_u/σ_v/σ_w 1,50/1,53/0,87 →
1,38/1,38/0,79, 300 м — 1,45/1,37/1,62 → 1,38/1,30/1,55 (сложение σ³ вместо σ²).
Спектр (turb_probe.gd --only=spectrum, spectrum.py; прямой полёт 12 м/с поперёк ветра
20 км/ч, Аушкуль aushtau_east, 400 с × 50 Гц; наклон log S — log f в 0,1–1 Гц ± 2σ по 8 частям):
| u, 150 м | w, 150 м | u, 400 м | w, 400 м | |
|---|---|---|---|---|
| с полем | −1,58 ± 0,13 | −1,70 ± 0,18 | −2,00 ± 0,27 | −1,68 ± 0,15 |
| аналитика | −2,90 ± 0,24 | −2,88 ± 0,12 | −2,96 ± 0,31 | −2,74 ± 0,13 |
Картинка — tools/research/air_turb/out/spectrum.png. Выше ~1,2 Гц (λ < 14 м при ~16 м/с
относительно шума) спектр обрезан — мельче размаха крыла не несём.
Болтанка от ветра, у бровки, в устойчивом воздухе (--only=table, СКО ряда 120 с в точке,
м/с, σ_u / σ_w; синтетическое поле — ровно, лог-профиль, H = 0; Синюха — поле lee_fields.py,
20 км/ч):
| Случай | 20 м | 100 м | 300 м |
|---|---|---|---|
| 2 м/с, нейтрально | 0,29 / 0,21 | 0,17 / 0,14 | 0,11 / 0,12 |
| 4 м/с | 0,82 / 0,38 | 0,39 / 0,32 | 0,32 / 0,28 |
| 6 м/с | 1,20 / 0,65 | 0,61 / 0,54 | 0,49 / 0,37 |
| 8 м/с | 1,61 / 0,83 | 0,85 / 0,68 | 0,63 / 0,49 |
| 6 м/с, N = 0,010 | 1,07 / 0,56 | 0,18 / 0,15 | 0,02 / 0,02 |
| 6 м/с, N = 0,018 (инверсия) | 0,82 / 0,44 | 0,07 / 0,06 | 0,01 / 0,01 |
| 6 м/с, H = 300 Вт/м², z_i = 1500 м | 1,87 / 0,71 | 1,16 / 0,88 | 1,32 / 1,06 |
| Синюха, ровно против ветра (−1400 м) | 1,36 / 0,56 | 1,26 / 0,62 | |
| Синюха, бровка (старт) | 2,06 / 0,78 | 1,10 / 0,84 | |
| Синюха, за гребнем +400 м | 1,30 / 2,66 | 3,13 / 2,18 |
Растёт с ветром (u* ∝ U), у бровки σ_u на 20 м в 1,5 раза больше, чем на равнине (разгон), в устойчивом воздухе выше приземного слоя почти гаснет (Ri ≫ 1), в конвекцию растёт к середине слоя. Аналитика на ровном месте в 1,5–2,5 раза сильнее: она подобрана под шероховатую местность (σ_u = 0,14·U·(1 + e^(−z/150))), поле — z0 = 0,1 м решателя (луг).
Подветренная зона против базы AM-00 (--only=lee: точка базы, 20 км/ч с обратной стороны,
180 с × 20 Гц, сид 42, погода medium с термиками; «рывок» — |dw/dt| > 3σ(dw/dt) ряда):
| Старт | база: σ_w, рывков/мин | с полем: σ_w, рывков/мин | порог dw/dt, м/с² база → поле | lee_f, U_out, ΔU |
|---|---|---|---|---|
| altai/sinyukha_west (10 м над землёй) | 1,14, 18,0 | 2,05 (+80 %), 15,0 (−17 %) | 2,0 → 3,4 | 1,0; 9,5; 8,5 м/с |
| askarovo/biyagoda_west (10 м) | 1,08, 7,3 | 2,05 (+90 %), 6,3 (−14 %) | 1,9 → 4,6 | 1,0; 9,9; 9,3 м/с |
| aushkul/aushtau_east (10 м) | 1,27, 26,0 | 1,66 (+31 %), 7,7 (−70 %) | 2,0 → 3,1 | 0,9; 8,2; 6,6 м/с |
Без поля — побитно база (1,139 / 18,0; 1,075 / 7,3; 1,274 / 26,0). Расхождения — физика:
- σ_w больше: (1) база гасила вертикальные пульсации у земли множителем agl/60 м (на 10 м — 0,17), а в приземном слое σ_w ≈ 1,25u* от высоты почти не зависит, в слое смешения — 0,14 ΔU; (2) ΔU из поля — скачок от 0,5–1 м/с у земли до 8–10 м/с над следом (ветер над гребнем разогнан и выше старта), а база брала ветер 5,6 м/с на высоте пилота.
- «Рывков» (выбросов за 3σ своей же производной) меньше на Аушкуле: сплошная болтанка слоя смешения сильнее, и те же удары вниз реже выходят за 3σ. В абсолютных числах толчков больше: выше порога базы (2 м/с²) — 84, 246, 66 в минуту. Удары вниз (форма базы) на месте, амплитуда — до ΔU.
Среднее w за гребнем = w поля ± шум (те же точки без термиков, 1800 с): с полем −0,18 / −0,15 / −0,26 м/с при w_mech поля + фон 0,03 / −0,23 / −0,14 м/с — разница 0,20 / 0,08 / 0,12 м/с при стандартной ошибке среднего ~0,4 м/с (σ_w 1,8–2,7 м/с, время корреляции рывков ~20 с); аналитика там же — −4,5…−4,6 м/с (эвристическое опускание 0,7·u·lee + рывки).
За гребнем после AM-08в (C4 v4; Онгудай, 6 выгрузок tools/research/wind_compare, таблица
«было / стало» — tools/research/wind_compare/am08v/table.md, am08v_table.py; поле и признак
отрыва те же, меняется только эвристика поверх поля; выгрузки — без болтанки, кроме *_turb_air):
| 9 м/с у земли | было | стало | поле |
|---|---|---|---|
| min w, старт 10 / 20 / 50 м | −13,0 / −18,2 / −16,4 | −0,9 / −1,2 / −1,8 | −0,8 / −1,0 / −1,4 |
| min w, седловина 10 / 20 / 50 м | −14,5 / −18,2 / −16,4 | −0,6 / −0,9 / −1,5 | −0,6 / −0,7 / −1,1 |
| среднее w в зоне, старт 10 / 50 / 100 м | +0,13 / −0,75 / −1,01 | −0,24 / −0,84 / −1,07 | −0,16 / −0,42 / −0,57 |
| возвратных точек, старт 10 / 20 м | 15,9 / 10,2 % | 3,2 / 1,8 % | 3,0 / 1,8 % |
| возвратных точек, седловина 10 / 20 м | 32,7 / 27,0 % | 17,0 / 13,8 % | 14,7 / 12,9 % |
| min продольной, старт / седловина 10 м | −4,7 / −4,7 | −0,5 / −2,2 | −0,5 / −2,2 |
air от поля по w отличается и фоновым опусканием погоды (−0,1…−0,5 м/с, у земли гаснет). При 3 м/с меняется только min w (рывки до проверки болтанки: −0,6 → −0,3 м/с на 10 м). Остаток возвратных точек сверх поля — эвристика там, где пузырь не разрешён: область 400 м вне окон и низкие бугры (r ≲ 70 м) в окне 50 м, добавка до −1,7 м/с. С болтанкой (*_turb_air, 40 моментов в точке; точки с lee_f > 0,5 и ΔU > 1 м/с): U_H 10–11 м/с, ΔU 3–7 м/с; на 10 м σ_w/ΔU 0,16–0,18 (≈ 0,14 слоя смешения + механическая), на 50–100 м 0,4–0,6 — там больше механическая болтанка сдвига над следом («Чего не умеет»); 3σ_w/U_H 0,3–0,5, крайний минимум из ~3000 значений (w − w поля)/U_H −0,54…−0,74 (≈ 4σ гауссова хвоста механической болтанки, не рывки: рывок ≤ 0,42 ΔU).
Пузырь отрыва (am08v_resolved.py → am08v/resolved.md; точки зоны lee_f > 0 на 10–50 м,
9 м/с, три области): доля точек, где поле само течёт назад, по L/dx = 2,8 r/dx — в окнах 50/100 м
0–2: 0 %, 2–4: 2 %, 4–6: 16 %, 6–8: 15 %, 8–10: 30 %, ≥ 10: 32 %; на области 400 м (L/dx < 4) —
0–3 %. Отсюда field_resolved_cells = [4, 8]: ниже 4 клеток решатель пузыря не даёт, с 8 —
частота насыщается; минимум u_прод/U_H поля в окнах −0,1…−0,43 (Menke: −0,22 ± 0,08).
Против базы AM-00 — наблюдение, не приёмка (решение пользователя: приёмка по физике, σ_w =
0,14·ΔU, Menke 2019; turb_probe.gd --only=lee, tools/research/air_turb/out/am08v/): σ_w с полем
Синюха / Бияготы / Аушкуль 0,86 / 0,77 / 0,44 м/с (база 1,14 / 1,08 / 1,27, до AM-08в 2,05 / 2,04 /
1,66), рывков выше 3σ 5,0 / 2,3 / 1,0 в минуту (база 18 / 7,3 / 26; до AM-08в 15 / 6,3 / 7,7); среднее
w без термиков −0,07 / −0,18 / −0,15 при w_mech поля + фон 0,03 / −0,23 / −0,14. Слабее базы на
25–65 %: ΔU от ветра на уровне гребня (у Аушкуля гребень над точкой низкий — U_H мал) вместо U_out.
Цена: air_velocity_at с полем (Каянча, 75 м, способ AM-00) — 48–50 мкс против 15 без поля
(до AM-08в на той же машине 48–50, tools/bench/air_velocity_bench.gd --kayancha; по сетке 6400
точек с полем 51–52 против 49 мкс, +4–7 %: в зоне отрыва — одна выборка поля на уровне гребня и
sample_dx); спектр 8 октав ~11 мкс, turb_at ~7 мкс. Без поля — побитно прежняя (38 400
значений, 0 отличий). Пилот (3 точки × 120 Гц) — ~2 % одного ядра.
Чего не умеет
- Шум переносится одним ветром (300 м над рельефом аналитики), не местным ветром поля: в тихом следе за гребнем вихри «пролетают» быстрее, чем в жизни (≈10 против 3–5 м/с) — в неподвижной точке частота порывов завышена; в полёте (12 м/с своей скорости) это слабее. У земли (ниже ~10 м) поправлено растяжением масштабов (AS-2, «Перенос вихрей у земли»); выше, в следе за гребнем — нет.
- Шум не несёт волн короче 14 м: у земли (L_w ≈ z = 1,5–3 м) вся σ_w приходится на вихри 14–30 м — крупнее, чем в жизни, и крыло (размах ~10 м, ветер берётся в одной точке) получает её целиком; настоящий порыв масштаба z крыло осредняет по размаху (σ_w на крыле ≈ 0,6 σ_w в точке при L_w = 2–3 м, размахе 10 м). Это граница модели полёта, не воздуха (AS-2, отчёт).
- Средний w у земли — w_mech поля, отмасштабированный лог-профилем от первой клетки: на склоне старта 0–0,5 от U·∇h настоящего рельефа (у земли поток идёт вдоль склона, w = U·∇h); сетка 50 м склон 15–20° передаёт не полностью.
- σ у земли — гауссов шум: при σ_u/U ≈ 0,35 (1,5 м, z0 = 0,1 м — подобие) обратный ветер на миг бывает (~0,4 % времени, событие > 2,7σ) — на 20-с отрезке редко.
- z0 = 0,1 м (луг) для всего поля: над лесом механическая болтанка занижена (u* ∝ 1/ln(z/z0)).
- Признак отрыва и слой смешения — по среднему полю RANS-подобного решателя. Возвратное течение решатель даёт сам, если пузырь отрыва покрыт ≳ 8 клетками (окна 50/100 м за гребнями выше ~70/140 м: у старта Каянчи при 9 м/с минимум продольной −0,5 м/с, у седловины −2,2 м/с ≈ 0,2 U_H, как в Perdigão); мельче (область 400 м, низкие бугры в окнах) — эвристика 0,22·U_H одной формой (e^(−agl/0,4r)), без длины и формы пузыря. Переход 4–8 клеток — smoothstep, не замер решателя на каждом гребне.
- Пузырь отрыва — по данным одной гряды (Perdigão: две параллельные гряды ~250 м, лес, нейтраль); на пологом подветренном склоне, где реального отрыва нет, эвристика (на грубой сетке) всё равно даёт обратный поток, если поле показывает след (lee_f > 0).
- Механическая болтанка в слое сдвига над следом (l·|∂U/∂z|) больше болтанки слоя смешения: на 50–100 м за гребнем σ_w/ΔU 0,4–0,6 вместо 0,14 (Онгудай 9 м/с, «Числа»); это замыкание длины перемешивания, не эвристика зоны — не подгонялось.
- Рывки — детерминированный шум заданной формы (не LES); их хвост распределения не выведен из физики, только амплитуда (пик 3σ_w = 0,42 ΔU), нулевое среднее и доля в σ_w.
- Аналитика (без поля, вне поля,
off, полоса края) — прежняя эвристика: опускание 0,7·u·lee и рывки 1,0·u·lee (danger_sink_per_wind,burst_per_wind) — от ощущения пилота, не из физики, в 3–5 раз сильнее слоя смешения (за гребнем при 9 м/с до −1,7·u = −10…−17 м/с); решение пользователя — не менять (AM-08в меняет только путь с полем). - Горизонтальные масштабы > 2,5 км шум не несёт отдельно — их доля дисперсии в верхних октавах.