Compare commits

..

4 Commits

4 changed files with 204 additions and 0 deletions

56
README.md Normal file
View File

@@ -0,0 +1,56 @@
# STM32 Audio Analyzer
STM32 Audio Analyzer — система реального времени для измерения уровня звука и доминантной частоты на базе STM32F103C8T6 (Blue Pill) с веб‑дашбордом и хранением истории в TimescaleDB.
Микроконтроллер оцифровывает сигнал с MAX4466, считает RMS (dBFS) и FFT (512 точек), отсылает метрики по USB CDC; на ПК коллектор пишет данные в PostgreSQL/TimescaleDB, FastAPI отдаёт REST/WS, Reactфронтенд показывает текущие значения и историю.
## Архитектура
- **[MCU (firmware)](firmware/README.md)**
- STM32F103C8T6, FreeRTOS, TinyUSB, CMSISDSP.
- ADC1 + DMA (circular, doublebuffer 2×512) с триггером от TIM3, частота дискретизации 22.05 кГц.
- Обработка: удаление DC, RMS в dBFS, Hannокно, RFFT 512, поиск пика 1008000 Гц.
- Передача каждые 100 мс пакетом 12 байт по USB CDC.
- **[Collector (Python)](services/collector/README.md)**
- Читает бинарный протокол с /dev/ttyACM0, ресинхронизация по SOF=0xAA.
- Проверка CRC8/ATM, диапазонов, подсчёт статистики ошибок.
- Запись в TimescaleDB (`audio_data`), параллельно пушит JSON по WebSocket (`ws://…/ws/live`).
- **[API (FastAPI)](services/api/README.md)**
- REST `/api/v1/audio/latest|range|export/csv`, `/api/v1/stats/summary`, `/api/v1/events/loud`.
- База: `audio_data` + непрерывный агрегат `audio_data_1min` (avg/max/min/доминирующая частота, доля тишины).
- **[Frontend (React)](services/frontend/README.md)**
- Liveдашборд: вертикальный аудио‑метр, peakhold за 3 секунды, история частоты, текущая нота.
- Источник данных — WebSocket `VITE_WS_URL`, REST для исторических запросов при необходимости.
## Структура репозитория
```text
.
├── README.md
├── docker-compose.yml
├── db/
│ └── init.sql # схема TimescaleDB + агрегаты/retention
├── firmware/ # прошивка STM32 (FreeRTOS + TinyUSB + CMSIS-DSP)
└── services/
├── collector/ # serial→WS→DB
├── api/ # FastAPI REST + DB
└── frontend/ # React/Vite дашборд
```
## Быстрый старт
```
git clone --recurse-submodules https://git.yolgins.ru/Iwwww/sound-analyze.git
```
```bash
cp .example.env .env
docker compose up --build
```
- БД: TimescaleDB на `localhost:5432` (`DB_NAME=audio_analyzer` по умолчанию).
- API: `http://localhost:8000/api/v1`.
- WebSocket коллектора: `ws://localhost:8001/ws/live`.
- Frontend: `http://localhost:3000` (devрежим Vite).

74
firmware/README.md Normal file
View File

@@ -0,0 +1,74 @@
# firmware/
## Цель
Прошивка для Blue Pill, которая снимает аудио с MAX4466, считает уровень в dBFS и доминантную частоту, мигает LED с частотой звука и публикует метрики по USB CDC в формате фиксированного бинарного пакета.
## Железо
- STM32F103C8T6 (Blue Pill, 72 МГц, 64К Flash, 20К RAM).
- Микрофон: MAX4466 (выход → **PA1 / ADC1_IN1**, питание 3.3 В).
- USB FS через TinyUSB CDC (Virtual COM).
- Светодиод: PC13 (on = 0, off = 1).
## Обработка аудио (DSP)
- Частота дискретизации: 22050 Гц (`AUDIO_SAMPLE_RATE`).
- DMAбуфер: 2×512 выборок `uint16_t` (двойная буферизация через half/full interrupt).
- RMS считается по формуле \(\mathrm{RMS} = \sqrt{\frac{1}{N}\sum\_{i=1}^{N} x_i^2}\) после удаления среднего и нормализации к диапазону около \([-1, 1]\).
- Перевод в dBFS: \(\mathrm{dBFS} = 20 \log\_{10} (\mathrm{RMS} + \varepsilon)\), где \(\varepsilon\) — малый стабилизатор для нуля.
- FFT: `arm_rfft_fast_f32` на 512 точках, Hannокно рассчитывается “на лету” через `arm_cos_f32`.
- Поиск пика по модулю `mag[k]` в диапазоне частот 1008000 Гц, шаг частоты \( \Delta f = \frac{22050}{512} \approx 43 \text{ Гц} \).
## Протокол
Пакет фиксированного размера 12 байт:
```c
// firmware/App/Inc/protocol.h + protocol.c
[SOF=0xAA][TYPE=0x02][LEN=0x08]
[timestamp_ms: uint32]
[rms_db_x10: int16] // dBFS * 10, ожидается -50.0 .. 0.0
[frequency_hz: uint16] // 100 .. 8000
[crc8: uint8] // CRC-8/ATM
```
- CRC: CRC8/ATM (poly=0x07, init=0x00, без отражения), считается по байтам с индексами 1..10.
## FreeRTOS задачи
- `audio_process_task`
- Ждёт уведомление от ISR DMA, обрабатывает последний буфер (512 сэмплов).
- Вычисляет метрики, обновляет режим LED, отправляет метрику в очередь для USBзадачи.
- `cdc_task`
- Читает из очереди, упаковывает в `protocol_pack_v1`, пишет в USB CDC, целевая частота ~10 Гц.
- `health_led_task`
- Настраивает PC13 и мигает в зависимости от частоты/уровня сигнала, плюс подкармливает watchdog.
## Сборка и прошивка
- Зависимости: `arm-none-eabi-gcc`, `make`, `st-flash`.
- Сборка:
```bash
cd firmware
make
```
- Прошивка (через STLink):
```bash
make flash
```
## Зависимости
| Библиотека | Путь | Репозиторий |
| ------------------- | -------------------------------------------- | ------------------------------------------------------------------- |
| **CMSIS-Core** | `firmware/Drivers/CMSIS/Core` | [ST GitHub](https://github.com/STMicroelectronics/cmsis_core)
| **CMSIS-Device F1** | `firmware/Drivers/CMSIS/Device/ST/STM32F1xx` | [ST GitHub](https://github.com/STMicroelectronics/cmsis_device_f1) |
| **FreeRTOS** | `firmware/Middlewares/FreeRTOS` | [FreeRTOS-Kernel](https://github.com/FreeRTOS/FreeRTOS-Kernel) |
| **TinyUSB** | `firmware/Middlewares/TinyUSB` | [hathach/tinyusb](https://github.com/hathach/tinyusb) |
| **CMSIS-DSP** | `firmware/Middlewares/CMSIS-DSP` | [ARM-software/CMSIS-DSP](https://github.com/ARM-software/CMSIS-DSP) |

40
services/api/README.md Normal file
View File

@@ -0,0 +1,40 @@
# services/api
## Назначение
FastAPIсервис поверх TimescaleDB, который предоставляет RESTдоступ к аудио‑метрикам и агрегированным статистикам.
## Основные endpointы
- `GET /api/v1/audio/latest?limit=100`
- Возвращает последние N точек `audio_data`.
- `GET /api/v1/audio/range?from=<ts>&to=<ts>`
- Данные за заданный интервал, проверка `from < to`.
- `GET /api/v1/stats/summary?period=1h`
- Агрегированная статистика (avg/max/min по dB, доминантная частота, процент тишины) по окну (`10s|1m|1h|6h|24h|7d|30d`).
- `GET /api/v1/events/loud?threshold=-35&from=<ts>&to=<ts>`
- “Громкие” события, где `rms_db` выше порога, опционально с интервалом времени.
- `GET /api/v1/export/csv?from=<ts>&to=<ts>`
- Экспорт диапазона в CSV: `time,rms_db,frequency_hz,is_silence`.
- `GET /api/v1/health/live` / `ready`
- Примитивный healthcheck и проверка доступности БД.
## Модель данных
Таблица `audio_data` в TimescaleDB:
```sql
CREATE TABLE audio_data (
time TIMESTAMPTZ NOT NULL,
rms_db REAL CHECK (rms_db >= -50.0 AND rms_db <= 0.0),
frequency_hz INTEGER CHECK (frequency_hz >= 100 AND frequency_hz <= 8000),
is_silence BOOLEAN NOT NULL DEFAULT FALSE
);
```
Плюс continuous aggregate `audio_data_1min` и политики retention/refresh.

View File

@@ -0,0 +1,34 @@
# services/collector
## Назначение
Сервис, который читает бинарные пакеты с STM32 через USB CDC, валидирует и логирует их, пишет данные в TimescaleDB и рассылает в реальном времени по WebSocket.
## Основные компоненты
- `serial_reader.py` — асинхронное чтение порта `SERIAL_PORT` (`/dev/ttyACM0` по умолчанию), nonblocking read, reconnectлогика.
- `protocol_parser.py` — парсер протокола: поиск SOF, проверка длины, CRC8/ATM, конвертация `rms_db_x10` → float.
- `audio_validator.py` — проверка диапазонов: `rms_db ∈ [-50.0, 0.0]`, `frequency_hz ∈ [100, 8000]`, детекция и пометка тишины.
- `db_writer.py` — batchзапись в PostgreSQL/TimescaleDB (`audio_data`), батч по количеству/таймеру.
- `ws_app.py` + `ws_manager.py` — WebSocket сервер, который бродкастит последние метрики всем подписчикам.
- `monitor.py` — вывод статистики: пакетов/с, CRCошибки, lengthошибки, rangeошибки.
## Формат данных в WebSocket
```json
{
"time": "2025-12-25T19:00:00Z",
"rms_db": -18.5,
"freq_hz": 440
}
```
Время берётся по хосту при приёме пакета, а не из MCUтаймстампа, чтобы быть в одной временной зоне с БД.
## Конфигурация
Через переменные окружения (см. `.example.env` и `docker-compose.yml`):
- `SERIAL_PORT`, `BAUDRATE`.
- `DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`.
- `WS_HOST`, `WS_PORT` (по умолчанию `0.0.0.0:8000`, наружу проброшен как `8001`).