# Методическое пособие: WarWalk — картограф радиопокрытия

Стенд: маячок **E77-900MBL** (LoRa, 869.4625 МГц, SF7) стоит на точке и раз в
секунду шлёт короткий пакет; **ходок** с таким же E77 + GPS **NEO-M8N** идёт по
району и каждые 2 секунды пишет строку «координата + медиана RSSI». Из тысяч точек
рождается карта покрытия, на которой в натуральную величину видны радиофизические
явления: тень здания, зеркальная полоса от ангара, дифракция за углом, волновод
улицы, дыры покрытия. Это тот же метод, которым сообщество **TTN Mapper**
картирует The Things Network — только здесь ученики картируют **собственную** сеть
и крутят каждый параметр.

Полная теория и методика полевого выхода — в `WarWalk_writeup.md`. Это пособие —
**план проведения уроков**: как связать проект со школьной программой (физика,
математика, информатика, статистика) и как использовать два Python-стенда,
чтобы понять карту **до** и **после** выхода в поле:

- `warwalk_link_budget.py` — интерактивный бюджет линка (децибельная арифметика,
  граница покрытия, FSPL против реального города);
- `warwalk_sim_map.py` — симулятор карты покрытия из физики (тень здания,
  дифракция, лог-нормальный shadowing, дыры ниже чувствительности).

## Кто чем пользуется

1. **Инженер** отвечает за стенд: прошивки ролей BEACON/WALKER, GPS, развёртывание
   серверного стека (`warwalk-schema.sql`, Node-RED, Grafana — см. writeup §6).
2. **Учитель** проводит уроки-симуляции в классе и полевой выход по сценарию.
3. **Методист** привязывает параметры к темам программы и следит за «честностью»
   данных (цензура, systematic bias — см. Урок 5).

---

## Модуль 1. Физика: бюджет радиолинка и затухание

### Урок 1. Одна строка в децибелах: где кончается связь

* Тема: логарифмическая шкала (децибел), степенные зависимости, неравенство.
* Стенд: `warwalk_link_budget.py`. Параметры: `P_TX_DBM`, `SENS_BY_SF`, `n`.

**Ход работы.** Запустите `uv run warwalk_link_budget.py`. Ползунками поставьте
мощность 14 дБм, n = 2.0 (свободное пространство) — граница покрытия уедет на
километры. Теперь плавно увеличивайте n до 3.5 (город) и смотрите, как граница
(зелёная линия) стремительно приближается к маячку.

**На графике:**
```
 RSSI, дБм
  -50│╲ FSPL (n=2): пунктир, уходит далеко
     │ ╲___
     │     ╲╲___ реальный город (n=3.5): круто вниз
 -123├──────╳──────── чувствительность SF7
     │      ▲ граница покрытия здесь
     └──────┴──────────► расстояние (лог)
```

**Разбор.** Вся радиосвязь — одна строка сложения в децибелах:
`P_rx = P_tx + G_tx + G_rx − PL(d)`, связь есть, пока `P_rx > чувствительности`.
Потери на трассе растут по лог-дистанционной модели `PL(d) = PL(d0) + 10·n·lg(d/d0)`.
В свободном пространстве n = 2 (формула FSPL даёт ~91 дБ на 1 км при 869 МГц) —
бюджета хватило бы на сотни километров. В городе n ≈ 3–4, и та же связь рвётся в
сотнях метров. **Разница между формулой FSPL и реальной картой — и есть весь
смысл проекта.** Термометр справа показывает, из чего складывается EIRP и запас.

**Практическое задание.** По формуле границы (в коде функция `coverage_range_m`)
посчитайте на бумаге: во сколько раз изменится дальность, если поднять мощность на
6 дБ (то есть ×4) при n = 3? Проверьте ползунком. Почему ответ (×1.58) не ×4?

---

### Урок 2. SF, чувствительность и цена дальности

* Тема: компромиссы в инженерии, обратные зависимости, единицы времени.
* Стенд: `warwalk_link_budget.py` (ползунок SF). Параметр: `SENS_BY_SF`.

**Ход работы.** В стенде оставьте мощность фиксированной, двигайте ползунок SF от
7 до 12. Граница покрытия отодвигается с каждым шагом SF. Свяжите это с тем, что в
`WarWalker.ino` эфирное время пакета печатается в консоль при старте.

**Разбор.** Чувствительность приёмника SX126x зависит от коэффициента расширения
SF: каждый шаг даёт ~2.5–3 дБ (SF7 ≈ −123 дБм, SF9 ≈ −129, SF12 ≈ −137). Больше SF
= слышим слабее = дальше добиваем. Но плата за это — эфирное время: каждый шаг SF
удваивает длительность пакета. SF12 «видит» на ~14 дБ дальше SF7, но пакет висит в
эфире в ~8 раз дольше — при том же лимите duty cycle плотность выборки по маршруту
падает. Это фундаментальный компромисс LoRaWAN: дальность против ёмкости сети.

**Практическое задание.** Опыт из writeup §8.6: спланируйте прогулку на SF7 и на
SF10. Оцените заранее (по стенду) сдвиг границы покрытия в дБ, а по эфирному
времени — во сколько реже придётся ставить точки. Обсудите, когда какой SF выбрать.

---

## Модуль 2. Физика города: тени, дифракция, отражения

### Урок 3. Почему здание «съедает» сигнал: читаем карту до поля

* Тема: геометрическая тень, дифракция волн, интерференция.
* Стенд: `warwalk_sim_map.py`. Параметры: `BUILDINGS`, `n`, knife-edge модель.

**Ход работы.** Запустите `uv run warwalk_sim_map.py`. На карте — маячок (звезда) и
два здания (штриховка). Найдите за каждым зданием тёмную «тень» с плавными краями.
Меняйте показатель n и наблюдайте, как при большом n тени тонут в общем провале.

**На графике (вид карты сверху):**
```
        ▓▓▓ здание
   ●───▓▓▓░░░░  ← за зданием ТЕНЬ: резкий обрыв у контура,
 маячок  ▓▓▓ ░░    плавные края (дифракция заворачивает за угол)
```

**Разбор.** Здание в первой зоне Френеля — это не «чуть хуже», это −10…−25 дБ
разом (затенение, shadowing). За кромкой сигнал не обрывается в ноль, а заворачивает
по модели клинового препятствия (knife-edge): ~6 дБ у самой кромки, 15–25 дБ в
глубине тени — поэтому в симуляторе за зданием плавный градиент, а не чёрный
прямоугольник. Внутри контура здания сигнала «нет» (стена глушит) — модель рисует
это как дыру. **Ограничение модели, которое надо назвать вслух:** симулятор считает
одно препятствие = один экран и НЕ считает отражения и волновод улицы. Реальная
карта из поля покажет то, чего симулятор не знает, — и в этом главная учебная
ценность сравнения.

**Практическое задание.** В `BUILDINGS` добавьте третье здание вплотную к маячку.
Предскажите форму его тени ДО перезапуска (куда она ляжет относительно маячка?),
затем проверьте. Почему тень всегда направлена ОТ маячка, как от фонаря?

---

### Урок 4. Многолучёвка и почему прошивка отдаёт медиану

* Тема: интерференция, случайные процессы, робастные оценки (медиана vs среднее).
* Параметры: `MEDIAN_N` в `WarWalker.ino`, `rssiMedian()`; σ в симуляторе.

**Ход работы.** В `warwalk_sim_map.py` поставьте σ (shadowing) в 0 — карта гладкая.
Теперь поднимайте σ до 8–10 дБ и жмите «Новая прогулка» несколько раз: карта
«кипит», у каждой прогулки свои пятна. Сравните с реальностью: при ходьбе вдоль
ангара RSSI прыгает на ±5–10 дБ.

**Разбор.** Металлический ангар — почти зеркало: отражённый луч интерферирует с
прямым, шаг интерференционной картины λ/2 ≈ 17 см на 869 МГц. При ходьбе RSSI
«кипит» — это быстрые релеевские замирания. Прошивка поэтому отдаёт **медиану по 5
пакетам**, а не сырое значение: медиана давит случайные провалы, но не размазывает
настоящую ступеньку тени (в отличие от среднего, которое «утащило» бы один
выброс). В симуляторе гистограмма RSSI услышанных точек показывает колокол в дБ —
это лог-нормальность shadowing своими глазами.

**Практическое задание.** Дан ряд из 5 замеров RSSI: −95, −97, −96, −70, −98 (один
выброс от отражения). Посчитайте среднее и медиану. Какая оценка ближе к «настоящей»
силе сигнала −96 дБм и почему медиана устойчивее к выбросу?

---

## Модуль 3. Статистика и честность данных

### Урок 5. Дыра покрытия — тоже данные: цензура и ошибка выжившего

* Тема: цензурированные данные, systematic bias, полнота выборки.
* Стенд: `warwalk_sim_map.py` (чёрные дыры, метрика PDR). Параметр: `SENS_BY_SF`.

**Ход работы.** В симуляторе поставьте маленькую мощность (или большой SF-порог) —
на карте появятся чёрные области. Обратите внимание на число **PDR** в заголовке
карты (доля точек, где сигнал ≥ чувствительности). Уменьшайте бюджет — PDR падает,
чёрного больше.

**На графике:**
```
 Рисуем ТОЛЬКО услышанное        Рисуем И дыры (честно)
  ▓▓▓▓▓▓▓ всё «зелёное»           ▓▓▓░░░●●● чёрные дыры видны
  карта врёт в плюс               худшие места на карте есть
```

**Разбор.** Прибор физически не может измерить RSSI ниже своей чувствительности —
там пакетов просто нет. Это **цензурированные данные**. Если рисовать только
услышанное, карта систематически врёт в оптимистичную сторону: худших мест на ней
не будет вовсе — классическая **ошибка выжившего** в буквальном радиоэфире. Поэтому
ходок логирует окна с нулём пакетов (`heard=0`, `n_fox=0`), на карте они чёрные, а
дашборд считает отдельную метрику PDR. Правильная пара карт: «RSSI там, где слышно»
+ «карта доставки». Для школьников это первое честное знакомство с systematic bias.

**Практическое задание.** Придумайте бытовой пример ошибки выжившего (подсказка:
отзывы о товаре, «дедушка курил и дожил до 90»). Объясните, как в WarWalk чёрные
точки-дыры играют роль «тех, кто не оставил отзыв».

---

### Урок 6. Выборка по пространству и передискретизация

* Тема: частота дискретизации, теорема отсчётов, агрегация данных.
* Параметры: `TX_PERIOD_MS`, `LOG_PERIOD_MS`, `MEDIAN_N`; вьюха `warwalk_grid`.

**Ход работы.** Разбор по коду и SQL (без нового запуска). Посчитайте с классом шаг
выборки: маячок 1 Гц, пешеход ~1.4 м/с → отсчёт каждые ~1.4 м; GEO-строка каждые
~3 м. Сравните с масштабами замираний из writeup §3.4.

**Разбор.** Замирания живут на двух масштабах: быстрые (многолучёвка) — сантиметры,
медленные (затенение) — десятки метров. Критерий Ли: усреднять по окну ~40 длин
волн (≈14 м на 869 МГц), чтобы убрать быстрые и оставить тень. Наши ~3 м/строку —
это **передискретизация**, и это правильно: лишнее можно проредить и агрегировать
на этапе визуализации (сетка 10 м во вьюхе `warwalk_grid` берёт медиану по ячейке),
а вернуть выброшенное — нельзя. Тот же принцип, что и в звуке/видео: «мельче, чем
надо» безопаснее, чем «крупнее, чем надо».

**Практическое задание.** Вьюха `warwalk_grid` округляет координаты до 4 знаков
(~11 м по широте). Почему берётся именно медиана по ячейке, а не среднее и не
максимум? Что случится с картой, если в ячейке взять максимум RSSI?

---

### Урок 7. Ловушка тепловых карт: плотность ≠ сила сигнала

* Тема: взвешенные визуализации, артефакты представления данных.
* Стенд: `warwalk_csv2map.py --heatmap`; вьюха `warwalk_grid`.

**Ход работы (демонстрация ловушки).** Возьмите учебный лог, где много точек стоят
в одном месте со слабым сигналом. Постройте heatmap «в лоб» по сырым точкам — там,
где топтались, вспыхнет фальшивое «горячее пятно». Затем постройте heatmap через
сетку-медиану — пятно исчезнет.

**Разбор.** `folium.HeatMap` и heatmap-слой Grafana — это карты **плотности** со
взвешиванием: где точек больше, там «горячее», даже при слабом сигнале. Лечение уже
встроено: слой строится не по сырым точкам, а по сетке ~10 м с медианой в ячейке
(`grid_median()` в Python, вьюха `warwalk_grid` в SQL) — плотность посещения
перестаёт влиять на цвет. Это важный урок о том, что визуализация может врать не
из-за данных, а из-за способа их показать.

**Практическое задание.** Объясните, почему для честной интерполяции поля
(«как у взрослых») нужен QGIS с IDW/кригингом, а не heatmap, — и почему изолиния,
проведённая интерполяцией сквозь здание, есть **артефакт метода** (см. writeup §5,
уровень 3). Что важнее на защите проекта: красивая карта или умение назвать её
ограничения?

---

## Приложение: таблица переноса концепций в индустрию

| Концепция из проекта | Где встречается за пределами лаборатории |
|---|---|
| Бюджет линка в дБ | Проектирование сотовых сетей, Wi-Fi, спутниковой связи |
| Лог-дистанционная модель, показатель n | Планирование покрытия, site survey |
| Дифракция knife-edge, зоны Френеля | РРЛ-пролёты, планирование вышек, оптика |
| Медиана vs среднее (робастность) | Обработка сенсоров, финансы, контроль качества |
| Цензурированные данные, ошибка выжившего | Медицина, соцопросы, надёжность, ML-датасеты |
| Передискретизация и агрегация | Обработка сигналов, ГИС, big data |
| Артефакты heatmap/интерполяции | Дата-журналистика, ГИС, научная визуализация |

## Заключение

WarWalk превращает невидимое радиополе в карту, которую можно потрогать ногами, и
на этой карте по очереди проступают темы из четырёх дисциплин: децибельная
арифметика и затухание (физика), лог-дистанционная модель и аппроксимация
(математика), медиана и агрегация (статистика), протокол и серверный конвейер
(информатика). Два Python-стенда дают понять карту **до** выхода в поле — `link_budget`
показывает, где кончится связь, `sim_map` показывает, откуда возьмутся тени и дыры,
— а настоящая прогулка добавляет то, чего модели не знали: отражения, волновод,
шум города. Разница между предсказанием модели и картой из поля — не ошибка, а
самый ценный результат проекта, и умение назвать эту разницу вслух дороже любой
красивой картинки.
