#pragma once #include #include #include #include #include namespace esp32_doa { using Complex = std::complex; struct Config { int sample_rate = 48000; int channels = 8; int nfft = 512; int hop = 256; double sound_speed_m_s = 343.0; double radius_m = 0.056; double min_frequency_hz = 500.0; double max_frequency_hz = 4000.0; int grid_points = 360; double diagonal_loading = 1e-2; std::vector microphone_azimuths_deg = { 157.5, 202.5, 247.5, 292.5, 337.5, 22.5, 67.5, 112.5}; }; struct Stft { int sample_count = 0; int snapshots = 0; int bins = 0; int channels = 0; // Layout is [snapshot][frequency bin][channel]. std::vector spectra; Complex &at(int snapshot, int frequency, int channel); const Complex &at(int snapshot, int frequency, int channel) const; }; struct DoaResult { double angle_degrees = 0.0; double peak_sharpness = 0.0; std::vector spectrum; }; struct MvdrResult { std::vector audio; }; Stft analyze_stft(const std::vector &audio, int sample_count, const Config &config); DoaResult srp_phat(const Stft &stft, const Config &config); DoaResult norm_music(const Stft &stft, const Config &config); MvdrResult mvdr(const Stft &stft, const Config &config, double angle_degrees); // Convenience functions for callers that already have samples in row-major // samples x channels form. DoaResult estimate(const std::vector &audio, int sample_count, const Config &config, const std::string &algorithm); MvdrResult beamform(const std::vector &audio, int sample_count, const Config &config, double angle_degrees); } // namespace esp32_doa