AtomSpectra · Тест стабильности тракта ESP32 · 2026-07-03 → 2026-07-04

STAB-2 / WF-1 — Стабильность тракта платы
+ валидация фикса auto-suspend

Пройден — фикс подтверждён #FW-19 обнаружен
9.40
Часов чистого прогона
0
Ребутов после фикса
0
Потерянных сегментов
0.50%
Макс. дрейф |Δ|
§1

Цель

#STAB-1 (USB напрямую, минуя плату) показал: детектор AtomSpectra стабилен — источник аномалии #FW-16 (выброс ~8100 с) не в детекторе. #STAB-2 повторяет измерение через плату с телеметрией firmware-кольца, чтобы: (1) привязать аномалии к системным событиям платы, (2) провалидировать фикс #WF-1 (CONFIG_SPI_FLASH_AUTO_SUSPEND выкл, commit 33fb4a4) — до фикса плата уходила в краш-луп под нагрузкой записи водопада.

Вывод: фикс подтверждён — 9.40 ч непрерывной записи без единого ребута и без потерь сегментов. Попутно обнаружена отдельная, не связанная с #WF-1 проблема ёмкости экспорта (#FW-19, см. §6).

§2

Схема эксперимента

[AtomSpectra детектор] │ USB (внутри платы) ▼ [ESP32-S3 atomspectra-gw] ── WiFi ──► [PC Windows 11] /api/spectrum.json stability_monitor_board.py /api/waterfall/status │ /api/system ├─ stability.csv (1 строка/окно) /api/devlog?since=N ├─ telemetry.jsonl (сырой снапшот wf/system) └─ devlog.txt (лог платы)

В отличие от #STAB-1, плата в схеме присутствует — сигнал измеряется через её HTTP API. Метод изолирует именно тракт ESP32 (USB-приём от детектора → буфер → WiFi → HTTP), поскольку сам детектор уже подтверждён стабильным.

§3

Методология и телеметрия платы

Формула центроида и классификация окон — без изменений от #STAB-1:

centroid = Σ(ch × counts[ch], ch = 1100..1899) / Σ(counts[ch], ch = 1100..1899) Δ% = 100 × (centroid − baseline_median) / baseline_median

Baseline — первые 5 окон (до первого BOARD_REBOOT); baseline_median = 1435.5321 кан. Действует на весь прогон.

Телеметрия платы (новое относительно #STAB-1)

ПолеИсточникСмысл
seg_dropped/api/waterfall/statusпотери flash-сегментов водопада — целевая метрика фикса #WF-1
seg_count/api/waterfall/statusролловеры сегмента
hist_drop/api/spectrum.jsonпотери при HTTP-фетче гистограммы — независимо от seg_dropped
uptime_sec/api/systemBOARD_REBOOT / SNTP_LIKELY

seg_dropped и hist_dropразные счётчики разных подсистем. Первый чинил #WF-1 (путь «водопад → flash»), второй — путь «гистограмма → HTTP-ответ», вне объёма фикса.

§4

Результаты

Центроид пика Cs-137 — Фаза B (после фикса #WF-1)
Загрузка данных…

Каждая точка — окно 60 с, 526 окон за 9.40 ч. Три ребута предфиксовой прошивки (фаза A) на графике не показаны — данные до фикса не входят в измерительный ряд.

Отклонение Δ% центроида от baseline-медианы (1435.5321 кан.)
Загрузка данных…

Порог аномалии ±2.0%. Пунктир — нулевая линия. Запас ≥4×.

Фаза A — репро краш-лупа (предфиксовая прошивка)

СобытиеUTC
Старт скрипта2026-07-03 20:47:40
BOARD_REBOOT #12026-07-03 20:56:18 (+8.6 мин)
BOARD_REBOOT #22026-07-03 21:24:12
BOARD_REBOOT #3 / фикс залит2026-07-03 22:05:35

Фаза B — чистый прогон после фикса

СобытиеUTC
Первое окно после фикса2026-07-03 22:06:39
Конец теста2026-07-04 07:30:43
Продолжительность9.40 ч (33 845 с)
BOARD_REBOOT за весь период0

Центроид (каналы, Фаза B)

ПараметрЗначение
Baseline медиана1435.5321
Mean (526 окон)1434.6762
Стд. отклонение2.0863 кан.
Min1428.3771
Max1439.9996

Дрейф Δ% (Фаза B)

ПараметрЗначение
Mean−0.0596%
Стд. отклонение0.1453%
Min (макс. отрицат.)−0.4984%
Max (макс. положит.)+0.3112%
Максимальный |Δ|0.4984%
Порог аномалии±2.000%
Запас до порога≥ 4×

Метрики #WF-1 (Фаза B)

МетрикаЗначение
seg_dropped (потери flash-сегментов)0
SEG_ROLLOVER событий52 (чистые)
RING_OVERFLOW событий0
BOARD_REBOOT событий0
§5

Артефакт: hist_drop — не потеря сегментов

За Фазу B hist_drop вырос суммарно на 1239 (скорость ~2.20/мин). Это не регрессия фикса #WF-1 — счётчик относится к другой подсистеме (см. §3): пропуски при фетче /api/spectrum.json, не при записи в flash. Аналогично артефакту дублирования чанков USB в #STAB-1 — на центроид не влияет (взвешенное среднее иммунно), что подтверждается 0 ANOMALY во всех 526 окнах при ненулевом hist_drop.

§6

Артефакт: экспорт ограничен ёмкостью flash-кольца (#FW-19)

При выгрузке n42-экспорта записанного водопада после теста файл содержал только 256 строк (~4.27 ч при кадансе ~60с/строка) вместо полных 9.40 ч чистого прогона.

Причина — ring_capacity=256 (поле /api/waterfall/status): flash-кольцо физически хранит только последние 256 строк. К концу теста накоплено total_rows=568 — кольцо перезаписало первые ~312 строк (~5.2 ч) новыми задолго до выгрузки.

Это не регрессия #WF-1seg_dropped остаётся 0, т.е. сама запись не теряет данные; ограничение — в объёме хранения. Событие RING_OVERFLOW не сработало ни разу — его условие детектирует лаг записи, не факт перезаписи кольца.

Практическое следствие: записи длиннее ~4.25 ч требуют периодического pull через /api/waterfall (клиент #REC-11) до заполнения кольца. Зарегистрировано как #FW-19 (задача #32, pending).

§7

Импликации

#STAB-2 → закрыт. Тракт ESP32 (постфикс) не вносит дрейфа усиления сверх ожидаемого шума измерения (0.50% макс. при пороге 2.0%). Аномалия #FW-16 была следствием краш-лупа/гонки записи флеша — устранена фиксом #WF-1.

#WF-1 → закрыт. Фикс (CONFIG_SPI_FLASH_AUTO_SUSPEND выкл, commit 33fb4a4) подтверждён: 0 ребутов, 0 потерянных сегментов за 9.40 ч под реальной нагрузкой. До фикса — ребут каждые ~15 мин.

#FW-19 → новая задача (pending). Экспорт водопада ограничен ёмкостью flash-кольца (256 строк, ~4.25 ч) — требует увеличения буфера или периодического pull для длинных записей.