docs: добавлены README.md
This commit is contained in:
56
README.md
Normal file
56
README.md
Normal 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)**
|
||||||
|
- STM32F103C8T6, FreeRTOS, TinyUSB, CMSIS‑DSP.
|
||||||
|
- ADC1 + DMA (circular, double‑buffer 2×512) с триггером от TIM3, частота дискретизации 22.05 кГц.
|
||||||
|
- Обработка: удаление DC, RMS в dBFS, Hann‑окно, RFFT 512, поиск пика 100–8000 Гц.
|
||||||
|
- Передача каждые 100 мс пакетом 12 байт по USB CDC.
|
||||||
|
|
||||||
|
- **Collector (Python)**
|
||||||
|
- Читает бинарный протокол с /dev/ttyACM0, ресинхронизация по SOF=0xAA.
|
||||||
|
- Проверка CRC‑8/ATM, диапазонов, подсчёт статистики ошибок.
|
||||||
|
- Запись в TimescaleDB (`audio_data`), параллельно пушит JSON по WebSocket (`ws://…/ws/live`).
|
||||||
|
|
||||||
|
- **API (FastAPI)**
|
||||||
|
- 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 + Vite)**
|
||||||
|
- Live‑дашборд: вертикальный аудио‑метр, peak‑hold за 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 <repo>
|
||||||
|
```
|
||||||
|
```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
74
firmware/README.md
Normal 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]` в диапазоне частот 100–8000 Гц, шаг частоты \( \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: CRC‑8/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
|
||||||
|
```
|
||||||
|
|
||||||
|
- Прошивка (через ST‑Link):
|
||||||
|
|
||||||
|
```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
40
services/api/README.md
Normal 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.
|
||||||
34
services/collector/README.md
Normal file
34
services/collector/README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# services/collector
|
||||||
|
|
||||||
|
## Назначение
|
||||||
|
|
||||||
|
Сервис, который читает бинарные пакеты с STM32 через USB CDC, валидирует и логирует их, пишет данные в TimescaleDB и рассылает в реальном времени по WebSocket.
|
||||||
|
|
||||||
|
## Основные компоненты
|
||||||
|
|
||||||
|
- `serial_reader.py` — асинхронное чтение порта `SERIAL_PORT` (`/dev/ttyACM0` по умолчанию), non‑blocking read, reconnect‑логика.
|
||||||
|
- `protocol_parser.py` — парсер протокола: поиск SOF, проверка длины, CRC‑8/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`).
|
||||||
Reference in New Issue
Block a user