fix: коэффициенты времени суток по методичке ПСО «Экстремум» (§12.3.3, §12.3.5)

Сверка с методикой ПСР ред. 12.17 (Евдокимов, Лейтес):
- ночь: 0.5 → 0.0 — методичка §12.3.5 прямо даёт «ночь = 0 км»:
  без фонаря в лесу ночью пострадавший не перемещается.
  Ранее 0.5 ЗАВЫШАЛО радиус ночного поиска.
- сумерки/вечер: 0.7 → 0.5 — «за час до заката скорость 50% от обычной».
  B5 переносил 0.7 из старого фронта вопреки методичке.
- get_base_speed: документирована семантика «скорость смещения»
  (не асфальтовая НормС из §12.3.2) — оператору не нужно вводить
  асфальтовую скорость, она уже свёрнута; СП = поправка конкретной
  местности поверх базового среднего леса.

Тесты обновлены под методичку, добавлен тест ночи = 0.
201 passed, 0 failed.
This commit is contained in:
2026-09-09 11:11:34 +03:00
parent 1119793145
commit 2d264a5779
2 changed files with 32 additions and 14 deletions
+8 -6
View File
@@ -85,8 +85,9 @@ class TestCalculateMaxDistance:
distance = calculate_max_distance(case_data)
# 3 * 1.5 * 0.2 * 0.85 * 0.5 * 0.7 = 0.27 km
assert distance == pytest.approx(0.27, rel=0.01)
# 3 * 1.5 * 0.2 * 0.85 * 0.0(ночь) * 0.7 = 0.0 км —
# методичка §12.3.5: без фонаря ночью движение = 0
assert distance == pytest.approx(0.0, rel=0.01)
def test_adult_heavy_rain_field(self):
"""Test for adult in heavy rain on field."""
@@ -193,12 +194,13 @@ class TestTimeOfDayCoefficient:
assert get_time_of_day_coefficient('день') == 1.0
def test_night(self):
assert get_time_of_day_coefficient('ночь') == 0.5
# Методичка §12.3.5: ночь = 0 (без фонаря движение прекращается)
assert get_time_of_day_coefficient('ночь') == 0.0
def test_twilight(self):
# B5: сумерки/вечер = 0.7 (было 0.5 — канон фронта)
assert get_time_of_day_coefficient('сумерки') == 0.7
assert get_time_of_day_coefficient('вечер') == 0.7
# Методичка §12.3.3: за час до заката скорость 50% от обычной
assert get_time_of_day_coefficient('сумерки') == 0.5
assert get_time_of_day_coefficient('вечер') == 0.5
class TestWeatherCoefficient:
+24 -8
View File
@@ -82,15 +82,25 @@ def get_base_speed(age: int) -> float:
"""
Get base movement speed by age (НормС).
ВАЖНО (семантика): в ВЕКТОРе это НЕ «нормальная скорость по асфальту»
из методички ПСО (§12.3.2, стандарт 5 км/ч), а уже готовая скорость
СМЕЩЕНИЯ потерявшегося по лесу: НормС_асфальт × СП, усреднённое
с учётом кружения/остановок/испуга. Канон перенесён из фронтового
расчёта (B5, 3e2692f) и согласован с априорами ПСО «Экстремум»:
400 случаев 2015 г., 94% найдены в пределах 3 км.
Следствие: в формуле ВЕКТОРА коэффициент СП применяется ПОВЕРХ этих
значений как поправка конкретной местности (густой лес < простой лес),
поэтому СП = 1.0 соответствует «среднему лесу», а не асфальту.
Оператору НЕ нужно вводить асфальтовую скорость — она уже свёрнута.
Args:
age: Age in years
Returns:
Base speed in km/h
Base displacement speed in km/h
"""
# Скорость смещения потерявшегося ребёнка (не скорость ходьбы)
# ПСО ЭКСТРЕМУМ: 94% найдены в пределах 3 км
# Скорость смещения потерявшегося ребёнка (не скорость ходьбы).
# Скорость смещения потерявшегося (не скорость ходьбы).
# Реальное смещение: испуг, кружение, остановки. Основа — ПСО ЭКСТРЕМУМ
# (400 случаев, 94% найдены в пределах 3 км). Значения перенесены из
# фронтендового расчёта как каноничные (согласовано с методологией).
@@ -203,10 +213,16 @@ def get_transport_coefficient(has_transport) -> float:
def get_time_of_day_coefficient(time_of_day: str) -> float:
"""
Get time of day movement coefficient (ВВС).
ВВС — влияние времени суток (методичка ПСО «Экстремум» §12.3.3).
- день: 1.0
- сумерки/вечер: 0.5 («за час до заката скорость 50% от обычной»)
- ночь: 0.0 — в примере §12.3.5 этап «ночь» даёт 0 км движения:
без фонаря в лесу ночью пострадавший не перемещается.
(Свет/фонарь/Луна — редкий случай, учитывается оператором вручную.)
Args:
time_of_day: Time of day
time_of_day: 'день' | 'сумерки' | 'вечер' | 'ночь'
Returns:
Time coefficient (0.0 - 1.0)
@@ -216,9 +232,9 @@ def get_time_of_day_coefficient(time_of_day: str) -> float:
time_lower = time_of_day.lower()
if 'ночь' in time_lower:
return 0.5
return 0.0
elif 'сумерки' in time_lower or 'вечер' in time_lower:
return 0.7
return 0.5
else: # день
return 1.0