This commit is contained in:
2026-07-01 15:33:49 +03:00
parent f93f4101c3
commit 873277e59f
7 changed files with 484 additions and 0 deletions

View File

@ -0,0 +1,33 @@
# CRC при сдвиге битов — симуляция (воспроизведение и оценка сжатия)
> Скрипт: `crc_shift_sim.py` (рядом). `crc8` точно как в `IR_config.cpp` (MSB-first, init=0xFF, без final-xor). `poly1=0x31`, `poly2=0x8C` (битовое зеркало 0x31). Модель ошибки: сдвиг битов в СЕРЕДИНЕ данных (бит-слип / циклический сдвиг), длина кадра сохраняется; «чек» сверяется как `check(искажённые данные) == check(оригинал)`. 200000 попыток на модель, данные 3/5/8 байт.
## 1. Твой исторический баг ВОСПРОИЗВЕДён
Одиночный CRC8 (один полином) реально пропускает сдвиг в середине пакета. Примеры (данные → сдвиг → искажённые):
- `26 0b 05``26 16 0a`: `crc1=0x78` совпал → **single ПРОШЁЛ**; двойная схема: `crc2 0xd8≠0x5c`**поймала**.
- `cc4fb8f633``cc5f71ec66`: `crc1=0x20` совпал → single прошёл; double поймала (`crc2 0xfc≠0x90`).
- `b983315b416440c3``b983315e82c88186`: `crc1=0x3a` совпал → single прошёл; double поймала.
## 2. Частота пропуска (доля НЕобнаруженных сдвигов)
| Схема | slip-delete | rotate-all | rotate-mid-window |
|---|---|---|---|
| **single** (1×CRC8, 8 бит) | 0.290.41 % | ~0.78 % | 0.550.78 % |
| **double** (2×CRC8, 16 бит) — текущая | **0.0070.015 %** | **0.0250.03 %** | **0.0080.026 %** |
| nibble-fold (4+4 бит) | 0.760.80 % | ~1.58 % | 1.181.55 % |
| nibble-trunc (4+4 бит) | 1.371.57 % | ~1.53 % | 1.221.57 % |
Вывод: **double примерно в 2040× надёжнее single** и ловит практически все сдвиги, которые single пропускает. Это подтверждает, зачем добавляли второй полином (0x8C = зеркало 0x31 ловит «зеркальные» сдвиговые ошибки, слепые для 0x31).
## 3. Идея «склеить 2 байта в 1» (полбайта на полином) — ХУЖЕ, чем есть
- **nibble-fold** (свернуть каждый CRC8 в 4 бита xor'ом) и **nibble-trunc** (взять по 4 бита) дают **0.61.6 % пропусков — это ХУЖЕ даже одиночного полного CRC8** и в ~50150× хуже текущей двойной схемы.
- Burst-ошибки (подряд искажённые биты — типичный IR-сбой: бит-слипы/всплески). Гарантия обнаружения = ширине контроля:
- single 8 бит и double — надёжны на коротких burst (≥8 бит), эмпирически в выборке не пропускали и длиннее;
- **nibble-fold** — гарантия ~4 бита (эмпирически до 7);
- **nibble-trunc** — **пропускает даже ОДИНОЧНЫЙ бит** (усечение теряет старший ниббл) → так делать нельзя.
## 4. Рекомендация
- **CRC — не то место, где стоит экономить байт.** Сжатие контроля до 1 байта повышает пропуск сдвигов/burst в ~50150× (с ~0.01 % до ~1 %) — прямо в том классе ошибок, ради которого второй полином и вводили.
- Если байт очень нужен — забирать его **не из CRC**, а из уже выявленного резерва: свободные `msgType` (3,5), «пустая» зона длины (компактные кадры), или переупаковка адресов/полей. 16-битный контроль (2×CRC8) сохранить.
- Если всё же сжимать CRC до 1 байта — только **fold (xor нибблов)**, никогда не truncate; и принять ~1 % пропуска на сдвигах (в ~50100× хуже текущего). Как отдельный компромисс — обсуждать вместе с обратной совместимостью.
(Обратную совместимость версий протокола обсудим отдельно — по запросу Даши.)