ESP-DSP 系列 1 | 用 IIR Biquad 打造高效數位濾波器
ESP-DSP 是 Espressif 官方推出的數位訊號處理函式庫,專為 ESP32 平台優化,能協助開發者快速實現常見的 DSP 任務,如濾波器、FFT、向量運算等功能。在物聯網(IoT)與嵌入式應用中,感測器資料經常受到環境雜訊、電源干擾或 ADC 精度限制影響,導致訊號跳動、漂移,進而影響判斷與控制準確度。
為了解決這些問題,數位濾波器(Digital Filters) 是最常見也最實用的解法之一。本篇文章將聚焦在 IIR(Infinite Impulse Response)Biquad 濾波器 的原理與在 ESP32 上的實作方式,並透過 ESP-DSP 套件中的 API,快速打造一個高效、低成本的資料清理流程。

內容
什麼是 ESP-DSP?
ESP-DSP 是 Espressif(樂鑫)官方推出的數位訊號處理(DSP, Digital Signal Processing)函式庫,專為 ESP32 系列晶片最佳化。它以 C 語言實作,針對 Tensilica Xtensa 處理器架構進行性能優化,支援浮點與向量化運算,能在資源有限的微控制器上執行高效能的數位訊號處理任務。
ESP-DSP 提供的功能包含:
- 常見的訊號視窗(Hann、Hamming、Blackman 等)
- IIR/FIR 濾波器(含 biquad)
- FFT / DFT 頻譜分析
- 向量與矩陣運算
- 統計與數學運算
IIR Biquad 是什麼?
IIR(無限脈衝響應)是一種常見的數位濾波器類型,相對於 FIR(有限脈衝響應)而言,它的記憶體使用量低、計算效率高,非常適合像 ESP32 這類資源有限的微控制器使用。
Biquad 是一種二階(second-order)IIR 濾波器結構,可透過多個 biquad 相連來建構更高階的濾波器。它的基本公式如下:
y[n] = b0·x[n] + b1·x[n−1] + b2·x[n−2] − a1·y[n−1] − a2·y[n−2]
其中:
x[n]是輸入資料y[n]是輸出資料b0,b1,b2,a1,a2是濾波器係數
開發環境
在開始編程之前,請確保已完成以下準備工作:
- 安裝 ESP-IDF 開發環境 (至少版本 v5.x 或更高)。
- ESP32 開發板。
- 安裝 ESP-DSP 函式庫。
專案結構
這是 ESP-IDF 預設的專案結構之一。當你使用 idf.py create-project 指令,或透過 VS Code 的官方 ESP-IDF 擴充套件建立新專案時,通常會看到這樣的配置:
esp32-iir-filter/
├── CMakeLists.txt
├── main/
│ ├── CMakeLists.txt
│ └── iir_filter_example.c
└── sdkconfig
程式實作
以下程式碼示範如何使用低通濾波器(Low-pass filter)去除感測器資料中的高頻雜訊,保留穩定且緩慢變化的訊號成分:
#include <stdio.h>
#include <math.h>
#include "esp_log.h" // ESP32 logging functions
#include "esp_dsp.h" // ESP32 DSP library main header
#include "dsps_biquad.h" // Biquad filter specific functions
// Constants and configuration
#define TAG "IIR_FILTER_GEN" // Tag for ESP logging
#define DATA_LEN 64 // Number of samples to process
// Global buffers
float input[DATA_LEN]; // Input signal buffer
float output[DATA_LEN]; // Filtered output buffer
float coeffs[5]; // Filter coefficients: [b0, b1, b2, a1, a2]
float w[2]; // Filter state variables (delay elements)
/* This implements the standard digital biquad filter design equations
* for a low-pass filter. Coefficients are normalized and formatted
* specifically for ESP-DSP's biquad implementation.
*/
void compute_lowpass_biquad(float fs, float fc, float Q, float *coeffs)
{
// Calculate angular frequency
float w0 = 2.0f * M_PI * fc / fs;
// Intermediate calculations
float alpha = sinf(w0) / (2.0f * Q);
float cos_w0 = cosf(w0);
// Calculate numerator coefficients (feedforward path)
float b0 = (1.0f - cos_w0) / 2.0f;
float b1 = 1.0f - cos_w0;
float b2 = b0; // Symmetrical coefficients
// Calculate denominator coefficients (feedback path)
float a0 = 1.0f + alpha;
float a1 = -2.0f * cos_w0;
float a2 = 1.0f - alpha;
// Normalize coefficients and format for ESP-DSP
// Note: ESP-DSP expects a1 and a2 to be negated
coeffs[0] = b0 / a0; // b0
coeffs[1] = b1 / a0; // b1
coeffs[2] = b2 / a0; // b2
coeffs[3] = -a1 / a0; // a1 (negated)
coeffs[4] = -a2 / a0; // a2 (negated)
}
void app_main(void)
{
ESP_LOGI(TAG, "Initializing ESP-DSP IIR Biquad Filter Example");
// Filter parameters
float fs = 1000.0f; // Sampling rate (Hz)
float fc = 30.0f; // Cutoff frequency (Hz)
float Q = 0.707f; // Quality factor (Butterworth response)
// 1. Compute filter coefficients
compute_lowpass_biquad(fs, fc, Q, coeffs);
// Log the computed coefficients
ESP_LOGI(TAG, "Generated Coefficients:");
ESP_LOGI(TAG, "b0 = %.4f", coeffs[0]);
ESP_LOGI(TAG, "b1 = %.4f", coeffs[1]);
ESP_LOGI(TAG, "b2 = %.4f", coeffs[2]);
ESP_LOGI(TAG, "a1 = %.4f", coeffs[3]);
ESP_LOGI(TAG, "a2 = %.4f", coeffs[4]);
// 2. Initialize filter state variables
w[0] = 0; // w[n-1]
w[1] = 0; // w[n-2]
// 3. Generate test signal (sine wave + random noise)
for (int i = 0; i < DATA_LEN; i++) {
// Fundamental signal component (50Hz sine wave)
float signal = 0.7f * sinf(2 * M_PI * i / 16.0f);
// Add uniform random noise (-0.1 to 0.1)
float noise = 0.2f * ((float)rand() / RAND_MAX - 0.5f);
input[i] = signal + noise;
}
// 4. Apply the biquad filter
// Parameters: input, output, length, coefficients, state variables
dsps_biquad_f32(input, output, DATA_LEN, coeffs, w);
// 5. Print input vs filtered results
ESP_LOGI(TAG, "Index\tInput\t\tFiltered");
for (int i = 0; i < DATA_LEN; i++) {
ESP_LOGI(TAG, "%2d\t% .4f\t% .4f", i, input[i], output[i]);
}
}
程式說明 :
這段程式使用的 compute_lowpass_biquad() 函數是根據二階 IIR(Biquad)低通濾波器的公式,依據三個參數來計算濾波器係數:
fs:取樣率(資料一秒來幾筆)fc:截止頻率(超過這個頻率的訊號會被濾掉)Q:品質因子,控制通帶的銳利程度(這裡用 0.707f 是標準設定)
產生出一組 5 個係數(b0, b1, b2, -a1, -a2)後,再透過 ESP-DSP 函式 dsps_biquad_f32() 把這個濾波器套用到感測器資料上。
Sine wave + random noise (amplitude 0.2)
編譯和燒錄
完成程式碼後,您可以使用 ESP-IDF 提供的命令進行編譯、燒錄和監控。
在 VS Code 的左下角 ESP-IDF 工具列:
- 點選 Build project
- 點選 Flash device
- 點選 Monitor device
輸出與測試結果
程式啟動後,可以從 ESP_Log 查看輸出結果 :
I (123) IIR_FILTER_GEN: Initializing ESP-DSP IIR Biquad filter example
I (124) IIR_FILTER_GEN: Generated coefficients:
I (124) IIR_FILTER_GEN: b0 = 0.0201
I (125) IIR_FILTER_GEN: b1 = 0.0402
I (126) IIR_FILTER_GEN: b2 = 0.0201
I (127) IIR_FILTER_GEN: -a1 = 1.5610
I (128) IIR_FILTER_GEN: -a2 = -0.6414
I (129) IIR_FILTER_GEN: Index Input Filtered
I (130) IIR_FILTER_GEN: 0 0.0874 0.0018
I (131) IIR_FILTER_GEN: 1 0.2612 0.0141
I (132) IIR_FILTER_GEN: 2 0.4068 0.0437
I (133) IIR_FILTER_GEN: 3 0.5795 0.0913
I (134) IIR_FILTER_GEN: 4 0.7062 0.1564
I (135) IIR_FILTER_GEN: 5 0.8289 0.2377
I (136) IIR_FILTER_GEN: 6 0.9025 0.3302
I (137) IIR_FILTER_GEN: 7 0.9450 0.4270
I (138) IIR_FILTER_GEN: 8 0.9000 0.5193
I (139) IIR_FILTER_GEN: 9 0.8192 0.5990
結論
在處理感測器資料時,雜訊與不穩定訊號往往會影響系統判斷與控制準確度。透過 ESP-DSP 套件提供的 IIR Biquad 濾波器,我們可以在不犧牲執行效率與資源的情況下,實現即時、穩定的訊號清理。這使得 ESP32 成為物聯網與邊緣運算中,同時兼顧效能與成本的理想平台。
ESP-DSP 為 ESP32 提供了高效能的數位信號處理 (DSP) 能力,特別適合用於:
- 感測器資料濾波
- 音頻處理
- 信號分析
- 即時控制系統
透過 IIR Biquad 濾波器,開發者可以有效地去除信號中的雜訊,同時保持系統的即時性和低資源消耗。這使得 ESP32 成為物聯網和邊緣計算應用的理想選擇。









