ESP32 + INMP441: измерение частотной характеристики завершается неудачно, несмотря на воспроизведение импульсной развертPython

Программы на Python
Ответить
Anonymous
 ESP32 + INMP441: измерение частотной характеристики завершается неудачно, несмотря на воспроизведение импульсной разверт

Сообщение Anonymous »

Я пытаюсь измерить частотную характеристику микрофона INMP441 с помощью ESP32 и сценария Python. ESP32 захватывает 6000 выборок через I²S и отправляет их по последовательному каналу. Я воспроизвожу логарифмический импульсный сигнал длительностью 62,5 мс (300–15 000 Гц) из динамика моего ноутбука, используя Python (sounddevice.play()), а затем совместите записанный микрофонный сигнал с разверткой, чтобы вычислить передаточную функцию.
Однако полученный график частотной характеристики неверен — на нем либо видна ровная линия, либо неожиданные провалы, либо шумные артефакты. Я подозреваю, что развертка не фиксируется должным образом, но я не уверен, в чем проблема.
К сожалению, я не могу опубликовать свой код Arduino, но вот некоторая информация:
Соответствующая настройка Arduino
  • Микроконтроллер: ESP32
  • Микроконтроллер: INMP441 (цифровой микрофон I²S)
  • Частота дискретизации: 48 000 Гц
  • Размер буфера: 6 000 выборок (≈125 мс)
  • I²S конфигурация:

    I2S_MODE_MASTER | I2S_MODE_RX
  • I2S_BITS_PER_SAMPLE_32BIT
  • I2S_CHANNEL_FMT_ONLY_LEFT
[*]Поток данных:
  • ESP32 отправляет «ГОТОВО» по последовательному соединению
  • Затем захватывает 6000 сэмплов с микрофона
  • Применяет удаление и фильтрацию смещения постоянного тока
  • Отправляет необработанные образцы с плавающей запятой по последовательному каналу между «DATA_START» и «DATA_END»

Что, по моему мнению, может пойти не так
  • Несоответствие времени: ESP32 начинает запись до воспроизведения развертки, поэтому он может пропустить развертку полностью или захватить только ее часть.
  • Развертка недостаточно громкая: Возможно, развертка не достигает микрофона четко или микрофон находится слишком далеко от динамика.
  • Ошибка выравнивания. Если развертка не зафиксирована правильно, взаимная корреляция в Python не обнаружит правильную задержку, что приведет к смещению или пустому массиву Align_mic.
  • Оконные артефакты или артефакты БПФ. Если выравнивание отклонено хотя бы на несколько выборок, передаточная функция на основе БПФ будет искажена.
  • Как я могу гарантировать, что ESP32 захватывает развертку во время ее воспроизведения?
  • Есть ли лучший способ синхронизировать воспроизведение развертки и запись с микрофона без изменения кода Arduino?
  • Существуют ли передовые методы выравнивания и проверки захваченного сигнала перед вычисляем передаточную функцию?
  • правильно ли я вычисляю частотную характеристику?
это мой код на Python:
import numpy as np
import matplotlib.pyplot as plt
import serial
import time
import sounddevice as sd
from scipy.signal import chirp, correlate, windows

# === Configuration ===
FS = 48000
DURATION = 0.0625 # 62.5 ms
N_SAMPLES = int(FS * DURATION) # 3000 samples
NFFT = 8192
CALIBRATION_OFFSET = 120.0
SERIAL_PORT = 'COM8'
BAUD_RATE = 115200
SERIAL_TIMEOUT = 10

# === Generate Chirp Sweep ===
def generate_sweep():
t = np.linspace(0, DURATION, N_SAMPLES, endpoint=False)
f0 = 300
f1 = 15000
beta = np.log(f1 / f0) / DURATION
phase = 2 * np.pi * f0 * (np.exp(beta * t) - 1) / beta
sweep = np.sin(phase) * windows.hann(N_SAMPLES)
return sweep

sweep = generate_sweep()

# === Wait for ESP32 ===
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=SERIAL_TIMEOUT)
print("Waiting for READY from ESP32...")
while True:
line = ser.readline().decode('utf-8', errors='ignore').strip()
if line == "READY":
print("ESP32 is ready. Playing sweep...")
break

# === Play Sweep ===
sd.play(sweep, samplerate=FS)
sd.wait()

# === Receive Mic Signal ===
print("Waiting for DATA_START...")
raw_data = []
while True:
line = ser.readline().decode('utf-8', errors='ignore').strip()
if line == "DATA_START":
raw_data = []
continue
elif line == "DATA_END":
break
else:
try:
raw_data.append(float(line))
except ValueError:
continue
ser.close()

mic_signal = np.array(raw_data)
if len(mic_signal) < 6000:
print(f"⚠️ Only {len(mic_signal)} samples received — expected 6000.")
exit()

# === Align and Extract Sweep Segment ===
corr = correlate(mic_signal, sweep, mode='valid')
lag = np.argmax(corr)
aligned_mic = mic_signal[lag:lag + N_SAMPLES]

if len(aligned_mic) != N_SAMPLES:
print(f"⚠️ Alignment failed: got {len(aligned_mic)} samples instead of {N_SAMPLES}")
exit()

aligned_mic *= windows.hann(N_SAMPLES)

# === Compute Transfer Function ===
S = np.fft.rfft(sweep, NFFT)
M = np.fft.rfft(aligned_mic, NFFT)
H = M / (S + 1e-12)
freqs = np.fft.rfftfreq(NFFT, 1 / FS)

mag_db = 20 * np.log10(np.abs(H) + 1e-12) + CALIBRATION_OFFSET
phase_deg = np.angle(H, deg=True)

# === Plot Bode-style Frequency Response ===
plt.figure(figsize=(12, 6))

plt.subplot(2, 1, 1)
plt.semilogx(freqs, mag_db, label="Mic Frequency Response", color='blue')
plt.axhline(84.0, color='gray', linestyle='--', label="Reference SPL (84 dB)")
plt.ylabel("Magnitude [dB SPL]")
plt.title("Mic Frequency Response (External Sweep Playback)")
plt.grid(True, which='both', linestyle='--', alpha=0.5)
plt.legend()

plt.subplot(2, 1, 2)
plt.semilogx(freqs, phase_deg, label="Phase Response", color='green')
plt.xlabel("Frequency [Hz]")
plt.ylabel("Phase [°]")
plt.grid(True, which='both', linestyle='--', alpha=0.5)
plt.legend()

plt.tight_layout()
plt.show()


Подробнее здесь: https://stackoverflow.com/questions/798 ... eep-playba
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»