Lidar_Muxa/docs/ALGORITHM.md

324 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Алгоритм
Документ отвечает на вопросы из ТЗ, п. 5: какую проблему решает подход, какие данные
использует, как обрабатывается облако, как принимается решение, какие параметры на что влияют
и где границы применимости.
---
## 1. Какую проблему решаем
Тоннель метро — почти пустое однородное пространство. Классическая схема «обучить детектор
классов объектов» здесь не работает: размеченных примеров препятствий нет и быть не может
(нормы безопасности метрополитена), а объектом может оказаться что угодно — от кабеля и бутылки
до человека.
Значит, задача не «найти человека», а **описать нормальный тоннель и заметить всё, что в него
не вписывается**. Ровно этим занимается зрительная система и грибовидные тела дрозофилы,
поэтому архитектура собрана из её вычислительных схем.
Важно: берутся **схемы и параметры** коннектома, а не спайковая симуляция всех 139 тыс.
нейронов. Обоснование — в [CONNECTOME.md](CONNECTOME.md), раздел «Почему не полная симуляция».
---
## 2. Какие данные используются
Только облако точек лидара. Ни одометрии, ни IMU, ни карты, ни разметки.
Измеренные характеристики данных (`tools/inspect_bags.py`):
* 128 колец, элевация от −25.1° до +14.4°, неравномерная: у горизонта шаг 0.127°, по краям 0.45°;
* азимут: 3600 столбцов на 360° либо 1200 на 120°, шаг 0.1°, **два эха** на столбец;
* «нет эха» кодируется точным `(0, 0, 0)` — 38…62 % лучей кадра;
* система координат сенсора: вперёд = −Y, вправо = +X, вверх = +Z.
---
## 3. Обработка облака
### 3.1. RETINA — омматидиальная решётка
Фасеточный глаз — регулярная решётка направлений; вращающийся лидар устроен так же. Облако
переводится в **ретинотопический дальностный образ** `R(кольцо, азимут)`, и дальше всё считается
в нём, а не в неупорядоченном облаке. Это даёт и скорость (всё — операции над матрицами),
и возможность применять пространственные фильтры.
Три детали, без которых образ получается неверным:
1. **Слияние эх.** Из двух эх берутся ближнее (`r_near`) и дальнее (`r_far`). Различимы они
у 0.6…1.6 % лучей, но это как раз тонкие предметы и кромки: разнос p50 ≈ 2.5 м.
2. **Выпрямление скоса.** У каждого лазерного канала свой постоянный азимутальный сдвиг,
разброс достигает **15.6° (±78 столбцов)**. В сыром виде «столбец» не является направлением:
соседние кольца одного столбца смотрят в стороны, разнесённые на градусы, и любой
пространственный фильтр считает мусор. Образ выпрямляется целочисленным сдвигом строк;
остаточная угловая ошибка `p99 = 0.028°` — меньше половины шага решётки.
3. **Калибровка по данным.** Углы каналов, шаг развёртки и число эх восстанавливаются из первых
кадров, а не берутся из паспорта. Поэтому решение работает с обеими раскладками, которые
встречаются в датасете.
### 3.2. HALTERES — стабилизация «взгляда»
Прежде чем обрабатывать картинку, муха стабилизирует голову по сигналам жужжалец и оцеллий.
Здесь роль горизонта играет плоскость головок рельсов: она оценивается **в каждом кадре**
робастно (минимум в ячейке сетки → IRLS с мягким Хьюбером → повторная подгонка у найденной
плоскости → экспоненциальное сглаживание по кадрам).
Отсюда — система координат пути `(d, u, h)`: вперёд, поперёк, вверх от рельса. Крепление сенсора
не обязано быть жёстким: в датасете высота установки различается (1.31 м и 1.70 м), крен на
кривых доходит до 3° из-за возвышения наружного рельса, и всё это отслеживается покадрово.
Побочный, но важный продукт — **ожидаемая дальность до пола** для каждого луча:
$$r_\text{пол} = \frac{c}{d_z + a\,d_y - b\,d_x}$$
где `z = a·d + b·u + c` — плоскость пути, `(d_x, d_y, d_z)` — направление луча. Луч с
отрицательной элевацией обязан закончиться на полотне на строго определённом расстоянии; всё,
что обрывает его раньше, — предмет, стоящий на пути.
### 3.3. Осевая линия пути
На дальности 150 м кривая радиуса 1300 м уводит путь на 8.6 м вбок. Прямой коридор там
давно упёрся бы в стену, и вся дальняя зона превратилась бы в сплошное ложное срабатывание.
Ось оценивается по дрейфу центра сечения тоннеля: по срезам дальности берётся середина между
3-м и 97-м процентилями поперечной координаты, и через эти точки проводится дуга
`u(d) = c₁·d + c₂·d²`, где `c₂ ≈ 1/(2R)`.
Две поправки, которые определяют работоспособность:
* веса срезов **равные**, а не по числу точек: у ближних срезов точек в сотни раз больше,
и взвешивание по количеству полностью подавило бы дальние срезы, где как раз и содержится
кривизна;
* за горизонтом наблюдаемой дальности парабола продолжается **линейно**, по касательной, —
экстраполяция кривизны туда, где данных не было, даёт десятки метров ошибки.
Плюс два физических ограничения: радиус круче 300 м на перегоне не встречается, а скорость
изменения оси ограничена. Без них платформа станции, делающая свод резко несимметричным,
уводит оценку центра, и габарит заезжает прямо на платформу — это был источник почти всех
ложных тревог у станций.
### 3.4. LAMINA — ON/OFF и латеральное торможение
Работа идёт не с дальностью, а с **диспаритетом** `δ = 1/R`. Так правильно по двум причинам:
угловой размер предмета пропорционален `1/R`, и шум лидара в диспаритете почти однороден,
тогда как в дальности растёт квадратично.
Клетки L1 и L2 расходятся на два канала:
* **ON** = `max(δ − δ_окружения, 0)` — объект ближе окружения, то есть выступ;
* **OFF** = `max(δ_окружения − δ, 0)` — провал или отсутствие эха, то есть **окклюзионная тень
за предметом**. Тень часто во много раз крупнее самого предмета — именно она даёт шанс увидеть
мелкий объект на большой дальности.
Окружение — кольцо вокруг точки, вычисляемое двумя равномерными фильтрами (большое окно минус
вырезанный центр). Оба разделимы и работают за O(N), поэтому стоимость не зависит от размера окна.
Размер предмета в лучах меняется с дальностью на два порядка: человек даёт ~440 лучей на 20 м
и ~8 на 120 м. Поэтому окружение берётся **на трёх масштабах сразу** и отклики объединяются
максимумом — как у колонковых нейронов лобулы с разными размерами рецептивных полей,
сходящихся на один нисходящий нейрон.
### 3.5. MEDULLA и LOBULA PLATE — движение
**T4/T5** — элементарные детекторы движения, по четыре подтипа на направление; T4 читает ON-канал,
T5 — OFF. Вычислительно это коррелятор Хассенштайна–Райхардта: сигнал одного омматидия
задерживается и умножается на сигнал соседнего, разность двух таких произведений даёт
направленный отклик.
**LPTC (HS/VS)** суммируют выход тысяч T4/T5 и тем самым измеряют собственное движение.
Здесь это критично: колёсной одометрии нет, и скорость поезда неоткуда взять, кроме как из
самого потока. Реализовано в три ступени, от дешёвой к точной:
1. корреляция продольного профиля тоннеля (гистограмма дальностей, обелённая вычитанием
скользящего среднего и без ближней зоны — иначе корреляция залипает на нулевом сдвиге);
2. медианное приближение дальних фронтальных поверхностей (стены отбрасываются по градиенту
дальности вдоль строки);
3. уточнение **перепроекцией**: точки прошлого кадра сдвигаются вперёд на пробное `Δs`,
проецируются в решётку текущего кадра, и выбирается сдвиг с максимальной долей совпавших
лучей. Это и есть проверка широкопольного потока на согласие с моделью собственного
движения — то, чем заняты тангенциальные клетки.
Доля совпавших лучей заодно служит мерой доверия: измеренные 0.76…0.95 означают, что модель
движения описывает сцену, а стоящий поезд даёт ровно 0 км/ч.
**LPLC2** — детектор надвигания. Его дендриты разложены на четыре слоя так, что клетка отвечает
только на поток, расходящийся из центра её рецептивного поля, и подавляется однородным
широкопольным потоком, то есть отделяет «на меня что-то летит» от «я сам двигаюсь».
Вычислительно — дивергенция поля T4/T5.
### 3.6. LOBULA — кандидаты (LC11)
LC11 у мухи — детектор мелкого объекта: возбуждается компактным пятном, выделяющимся из фона,
и подавляется широкопольным узором. Здесь тем же занимается выделение кандидатов.
Лучи, попавшие в габарит, группируются в связные пятна — но с двумя принципиальными деталями:
* **связность с учётом разрыва по глубине.** Обычное соседство склеивает предмет со стеной,
оказавшейся в том же месте изображения, но на сто метров дальше. Два соседних луча
объединяются, только если их дальности близки; допуск растёт с расстоянием, потому что
и разрешение, и шум растут так же. Эта одна правка подняла обнаружение реального объекта
с 16/20 до 20/20 кадров и дала правильные габариты вместо слипшихся 5 × 4 м;
* **кластеризация по расширенной области, проверка членства — по габариту.** Вертикальный
лоскут стены, срезанный границей коридора, неотличим от предмета: обрезка сама создаёт
компактное пятно нужного размера. Поэтому пятна ищутся в объёме с запасом, а доля лучей,
оставшихся внутри габарита (`containment`), сразу показывает, предмет это целиком или край
стены. Расширение идёт в стороны и вверх, но **не вниз**: полотно проходит под каждым
предметом и на большой дальности попало бы в тот же допуск по глубине.
* **пол габарита в колее ниже, но не везде.** Между рельсами (|u| ≤ 0.85 м) нижняя
граница 0.16 м вместо 0.28 — иначе упавший на пути человек высотой 0.30 м виден
верхушкой в два сантиметра. Ближе 30 м пол прежний: там в полосу 0.16…0.28 м попадают
головки рельсов, рельс собирается в одну связную компоненту от самой кабины, и предмет,
коснувшийся его, выбрасывается вместе с ним (EXPERIMENTS п. 16.3).
Для каждого кандидата считаются: дальность, смещение от оси, высота нижней точки, габариты,
протяжённость вдоль пути, целостность, число лучей и колец, контраст, дефицит до пола,
доля тени и интенсивность.
**Разрез компоненты, растёкшейся вдоль стены.** Допуск по глубине решает задачу «предмет и
далёкая стена», но не обратную: вдоль **гладкой** стены соседние лучи отличаются на
сантиметры, и стена оказывается связной от ближнего поля до горизонта. Предмет у такой
стены попадает в ту же компоненту и отбрасывается вместе с ней правилом «ни один предмет
не тянется на 15 м вдоль пути».
Разорвать такую компоненту по дальности нельзя — предмет и стена рядом с ним стоят на одной
дальности. Зато гладкая стена даёт **нулевой центр-окружение по построению**: как бы сильно
дальность ни менялась вдоль стены, она меняется плавно, и центр равен окружению. Предмет на
стене — ступенька, и ламина её видит. Поэтому переглубокая компонента не выбрасывается, а
пересобирается по лучам с контрастом выше порога (`split_gap`, 6 м).
Выносится **ровно одна, сильнейшая фигура** (`split_top`). Это не косметика: разрез отрезает
фон, и протяжённость кандидата вдоль пути падает с 6.9 до 0.8 м — вместе с ней выключается
множитель компактности в весе улики, который до того давил протяжённые конструкции вдесятеро.
Ограничение — тот же приём глобального торможения, которым APL оставляет активными считанные
проценты клеток Кеньона. Измерено: одна фигура вместо всех даёт 6.4 ложных трека на километр
против 9.4 **при одинаковой дальности обнаружения**.
### 3.7. MUSHROOM BODY — память нормального тоннеля
Геометрия честно сообщает обо всём, что торчит в габарит, и вместе с препятствиями выдаёт
кабельные лотки, ниши, гермозатворы, кромки платформ и стрелочные приводы. Разделить их
геометрическим правилом нельзя — но можно **выучить, что для этого тоннеля привычно**.
Схема взята из коннектома почти без изменений:
1. **PN → KC.** Каждая клетка Кеньона получает вход от ~6 проекционных нейронов, выбранных
случайно, — разрежённая случайная проекция, поднимающая размерность в десятки раз.
2. **APL.** Один гигантский тормозный нейрон собирает активность всех KC и возвращает торможение
всем сразу: «победитель забирает всё», одновременно активны доли процента клеток.
3. **KC → MBON.** Синапсы депрессируются при повторном предъявлении, поэтому знакомый стимул
даёт слабый ответ, а новый — сильный. Ответ MBON и есть новизна.
Обучение идёт **без единой метки**: конвейер прогоняется по проездам пустого тоннеля, все
выданные геометрией кандидаты объявляются знакомой обстановкой.
Ключевая тонкость — **темп депрессии согласуется с размером выборки**. На одну клетку Кеньона
приходится `n · n_active / n_kc` попаданий; если темп не уменьшать вместе с ростом выборки,
после нескольких десятков тысяч примеров подавлены все синапсы и новым не выглядит уже ничто,
включая настоящее препятствие (проверено: при исходных параметрах новизна реального объекта
падала до 0.001). Темп выбирается так, чтобы типичная клетка ослабла в фиксированное число раз;
тогда шкала новизны отражает **частоту** обстановки, а не факт «видел хоть раз».
**Привыкание внутри проезда — сделано и выключено.** Всё вышесказанное работает,
только если память этот тоннель знает; на новом участке ложных треков 21.8 на
километр против 9.1. Попытка закрыть это короткой памятью, гасящей формы, которые
повторяются в разных точках пути, измерена и отвергнута: избирательности у механизма
нет, а видимый эффект оказался насыщением популяции, которое давит предмет сильнее
обстановки. Код и параметры оставлены (`enable_habituation`), разбор — EXPERIMENTS
п. 10.
### 3.8. CENTRAL COMPLEX — накопление улик
Кандидат на 150 м — это 5–10 лучей, и по одному кадру он неотличим от шума. Но поезд едет,
и настоящий объект остаётся **на одном месте в тоннеле**, а не в поле зрения.
Эллипсоидное тело мухи держит кольцевой аттрактор: клетки EPG образуют бугор активности,
клетки PEN сдвигают его по сигналам собственного вращения, взаимное торможение не даёт
возникнуть второму бугру. Здесь тот же механизм: треки живут в координате «путь от начала
записи», сдвигаемой оценкой собственного движения (роль PEN), совпадение подкачивает улику
(локальное возбуждение), несовпадение — утечка, конкуренция за место гасит дубликаты
(глобальное торможение).
Вес одного наблюдения:
$$q = \underbrace{\min\!\left(\frac{n_\text{лучей}}{n_\text{ожид}(d)},1\right)}_{\text{поддержка}}
\cdot \underbrace{\frac{\Delta R}{3}}_{\text{контраст}}
\cdot \underbrace{\frac{c-0.25}{0.45}}_{\text{целостность}}
\cdot \underbrace{\left(1.5-\frac{L}{3s}\right)}_{\text{компактность}}
\cdot \underbrace{\left(1.25-\frac{h_\text{низ}}{1.2}\right)}_{\text{опора снизу}}
\cdot \underbrace{g(\nu)^{w(R)}}_{\text{новизна}}$$
Все множители физичны:
* **поддержка** — число лучей нормируется на ожидаемое для этой дальности: дальний объект даёт
мало лучей не потому, что сомнительный, а потому что так устроена решётка;
* **компактность** — посторонний предмет не тянется на десятки метров вдоль пути, а лоток,
стена и полотно тянутся;
* **опора снизу** — упавший предмет, человек, камень стоят на полотне, а знак, лоток или
кронштейн висят на стене, и под ними пусто;
* **новизна** `g(ν)` — резкое отображение ответа MBON с ненулевым полом: даже похожий на
привычную конструкцию предмет должен накапливать улику, просто медленнее. Показатель
`w(R)` гасит этот множитель с дальностью: за 90 м он линейно сходит от 1 к 0.
Причина замерена, а не придумана — на 120…185 м новизна вставленного человека 0.150
против 0.199 у окружающей обстановки, то есть признак **перевёрнут**: на шести лучах
дескриптор вырождается, и память узнаёт в предмете любую далёкую конструкцию.
Гашение подняло обнаружение на 150 м с нуля до 0.32 (EXPERIMENTS п. 12.3).
### 3.9. DESCENDING NEURONS — решение
Весь разбор сцены у мухи сходится на нескольких десятках нисходящих нейронов. Два из них
работают по надвигающемуся объекту: **гигантское волокно (DNp01)** с высоким порогом запускает
немедленный аварийный манёвр, **DNp02/DNp11** с порогом ниже дают раннюю мягкую реакцию.
Поезду нужна такая же пара уровней: заблаговременное предупреждение с запасом по дальности
и экстренное торможение по надёжному близкому объекту. Пороги с гистерезисом — без него трек
на границе даёт дребезг, а дребезжащая команда торможения хуже её отсутствия.
Порог предупреждения зависит от дальности: до 90 м он 0.5, дальше линейно сходит к 0.3 на
200 м. Далёкая улика физически слабее — четыре-восемь лучей вместо сотни, — а цена ошибки ниже:
до предмета ещё сотня метров и десятки кадров на подтверждение. Экстренный порог не снижается
никогда. Это подняло обнаружение на 150 м с 0.33 до 0.37 без потерь ближе (EXPERIMENTS п. 15.9).
Решение принимается по улике трека, а не по среднему качеству его наблюдений, хотя улика
насыщается: у всего, что видно дольше пары секунд, она равна единице. Проверено три способа
учесть среднее — обученное считывание по треку, жёсткий порог и смешивание, — и ни один не
дал размена лучше простого порога на незнакомой линии (EXPERIMENTS п. 15.5–15.8).
Тормозной путь считается как `v·t_реакции + v²/(2a)` и сравнивается с дистанцией до объекта.
---
## 4. Какие параметры на что влияют
| Параметр | Эффект при увеличении |
|---|---|
| `half_width` | шире габарит → больше находок и больше ложных на кромках платформ |
| `h_lo` | выше порог → перестают ловиться низкие предметы (кабель, камень), меньше ложных от полотна |
| `h_lo_core` / `core_from` | пол между рельсами и дальность, с которой он опущен. Пол ниже → виден лежащий человек (0.30 м), но ближе 30 м в полосу 0.16…0.28 м попадают головки рельсов, и предмет выбрасывается вместе с рельсом (EXPERIMENTS п. 16.3) |
| `min_rays` | строже → пропадают дальние мелкие объекты, падает поток кандидатов |
| `fov_deg` | шире сектор → лучше кривые и стрелки, дороже обработка |
| `gain` / `leak` (CX) | быстрее подтверждение против устойчивости к шуму |
| `warn_evidence` | выше → меньше ложных тревог, позже обнаружение |
| темп депрессии MB | выше → сильнее подавление знакомого, но риск заглушить и настоящее |
---
## 5. Ограничения метода
Формулируем прямо, потому что скрывать их бессмысленно — они видны на данных.
1. **Дальность ограничена не алгоритмом, а геометрией.** Прямая видимость в предоставленных
тоннелях 121–167 м: тоннели кривые, дальше линия взгляда упирается в стену. Паспортные
200 м Pandar128 достижимы только на прямых участках.
2. **Память знает только то, что видела.** На новом участке тоннеля незнакомая штатная
конструкция получит высокую новизну. Поэтому новизна входит множителем, а не фильтром,
и решение опирается ещё на геометрию и накопление улик.
3. **Оценка оси пути требует видеть обе стены.** В широких залах и на станциях сечение
перестаёт быть тубусом вокруг пути; спасают физические ограничения на радиус и скорость
изменения оси, но точность там ниже.
4. **Очень низкие предметы на грани.** Кабель Ø 6 см даёт 9 лучей на 20 м и 2 на 40 м —
у самой границы разрешения прибора, не алгоритма.
5. **Скорость оценивается только продольная.** Боковой снос и вертикальные колебания
компенсируются стабилизацией плоскости, но в модель движения не входят.
6. **LPLC2 считается, но пока не влияет на решение** — канал надвигания подготовлен
и визуализируется, его вклад в улику ещё не откалиброван.