#pragma once
#include <Arduino.h>
/*
=========================================================
MAX4466 Microphone — драйвер для ESP32
Подключение: аналоговый выход на ADC-пин ESP32
Что умеет:
- Замер мгновенного уровня шума (dB SPL, приблизительно)
- EMA-сглаживание dB
- Динамика шума: скользящее среднее по минутам +
линейный тренд (как у LD2420)
- Пиковый уровень за окно наблюдения
- JSON состояния
Калибровка:
Абсолютные dB SPL зависят от усиления потенциометра
на модуле MAX4466 и акустики помещения.
Настройте db_ref_mv и db_ref_pa под ваши условия,
либо используйте относительные значения dB FS.
Как работает замер:
За каждый вызов update() снимается sample_count отсчётов
с интервалом sample_interval_us.
Вычисляется RMS амплитуды (после вычитания DC-смещения),
затем переводится в дБ.
=========================================================
*/
struct Max4466Config {
/* ---- Пин и ADC ---- */
uint8_t adc_pin = 34;
/*
Разрешение ADC ESP32: 12 бит → max = 4095.
Напряжение питания 3.3 В → 1 LSB ≈ 0.806 мВ.
*/
uint16_t adc_max_value = 4095;
float adc_vref_mv = 3300.0f; // мВ
/* ---- Сэмплирование ---- */
/*
Количество отсчётов за одно измерение.
Больше → точнее RMS, но дольше блокируется loop().
128–256 — хороший баланс для замера шума.
*/
uint16_t sample_count = 256;
/*
Пауза между отсчётами в микросекундах.
256 отсчётов × 100 мкс = ~25 мс на одно измерение.
*/
uint16_t sample_interval_us = 100;
/* ---- Интервал между измерениями ---- */
uint32_t read_interval_ms = 100;
/*
Через сколько мс без успешного чтения считать данные устаревшими.
*/
uint32_t stale_after_ms = 2000;
/* ---- EMA-сглаживание dB ---- */
/*
0.0 → почти без обновления (сильное сглаживание)
1.0 → без сглаживания
*/
float db_ema_alpha = 0.15f;
/* ---- Калибровка dB ---- */
/*
Опорное напряжение в мВ соответствующее 0 dB SPL (≈ 20 мкПа).
Подберите экспериментально или рассчитайте по даташиту
на MAX4466 при заданном усилении.
По умолчанию: 1 мВ RMS → 0 dB FS (относительные dB).
Если нужен абсолютный dB SPL — откалибруйте под усиление.
*/
float db_ref_mv = 1.0f;
/*
Нижний порог шума (dB): значения ниже считаются тишиной.
Компенсирует шум АЦП при полной тишине.
*/
float db_noise_floor = 30.0f;
/*
Диапазон шкалы noise_level (0..10).
noise_level = 0 соответствует db_noise_floor,
noise_level = 10 соответствует db_noise_floor + db_scale_range_db.
По умолчанию: 30 dB диапазон → каждый балл ≈ 3 dB.
*/
float db_scale_range_db = 30.0f;
/* ---- Динамика (тренд по минутам) ---- */
/*
Усреднение по секундам для activity_score (0–10).
Аналогично activity_avg_window_s у LD2420.
*/
uint8_t db_avg_window_s = 30;
/*
Окно тренда в минутах.
Минимум 2, максимум DB_TREND_MAX.
*/
uint8_t db_trend_window_min = 10;
/* ---- Пиковое значение ---- */
/*
Период сброса пикового значения (мс).
0 = никогда не сбрасывать автоматически.
*/
uint32_t peak_reset_ms = 60000;
};
/*
=========================================================
Max4466Mic — публичный интерфейс
=========================================================
*/
class Max4466Mic {
public:
Max4466Mic() = default;
/*
Инициализация: настройка ADC-пина.
Возвращает true всегда (аналоговый датчик не отвечает
на запросы — online определяем по наличию данных).
*/
bool begin(const Max4466Config &config);
/*
Периодическое обновление.
Нужно вызывать часто из loop().
*/
void update();
/* ---- Статус ---- */
bool is_online() const { return _online; }
bool has_valid_data() const { return _has_valid_data; }
bool is_stale() const;
/* ---- Текущие значения ---- */
/*
Мгновенный dB (сглаженный EMA).
*/
float get_db() const { return _db_filtered; }
/*
Сырой dB без EMA-фильтра.
*/
float get_db_raw() const { return _db_raw; }
/*
Усреднённый dB за db_avg_window_s секунд.
*/
float get_db_avg() const { return _db_avg; }
/*
Пиковый dB за период peak_reset_ms.
*/
float get_db_peak() const { return _db_peak; }
/*
RMS-напряжение последнего замера (мВ).
*/
float get_rms_mv() const { return _rms_mv; }
/* ---- Динамика ---- */
/*
Тренд уровня шума по минутам.
Возвращает: "increasing" / "decreasing" / "constant" / "variable"
*/
const char* get_noise_dynamics() const;
/*
Средний уровень шума за минуту в виде шкалы 0..10.
Вычисляется из db_avg относительно db_noise_floor и
db_noise_floor + db_scale_range_db.
*/
uint8_t get_noise_level() const;
/* ---- JSON ---- */
/*
Формат:
{
"online": true,
"current_noise": 65, // dB (мгновенный, EMA-сглаженный)
"noise_level": 4, // 0..10 (среднее за минуту)
"noise_level_dbi": 65, // dB (среднее за минуту)
"noise_dynamics": "constant"
}
*/
String get_state_json() const;
/* ---- Ручной сброс пика ---- */
void reset_peak();
private:
Max4466Config _config;
bool _online = false;
bool _has_valid_data = false;
uint32_t _last_read_ms = 0;
uint32_t _last_success_read_ms = 0;
uint32_t _last_peak_reset_ms = 0;
float _rms_mv = 0.0f;
float _db_raw = 0.0f;
float _db_filtered = 0.0f;
float _db_avg = 0.0f;
float _db_peak = 0.0f;
/* ---- Внутренние методы ---- */
float _measure_rms_mv();
float _rms_to_db(float rms_mv) const;
void _update_filtered_db(float db);
/* ---- Секундное усреднение (как act_avg у LD2420) ---- */
static constexpr uint8_t DB_AVG_MAX = 60;
float _db_avg_buf[DB_AVG_MAX] = {};
uint8_t _db_avg_idx = 0;
uint8_t _db_avg_count = 0;
uint32_t _db_avg_last_ms = 0;
void _tick_db_avg(uint32_t now_ms);
/* ---- Тренд по минутам (как _tick_trend у LD2420) ---- */
static constexpr uint8_t DB_TREND_MAX = 10;
float _trend_buf[DB_TREND_MAX] = {};
uint8_t _trend_idx = 0;
uint8_t _trend_count = 0;
uint32_t _trend_last_ms = 0;
int8_t _trend_slope = 0;
float _trend_std_dev = 0.0f;
void _tick_trend(uint32_t now_ms);
void _compute_trend();
};