ESP-DSP 系列 2 | 用 FIR 打造高效數位濾波器


ESP-DSP FIR 模組 是數位訊號處理(DSP)中不可或缺的濾波核心元件之一。FIR(有限脈衝響應,Finite Impulse Response)濾波器以其穩定性與線性相位特性,廣泛應用於音訊處理、通訊系統與感測器資料淨化等場景。本文將聚焦於 Espressif 提供的 FIR 模組,說明如何運用其高效能特性,打造穩定且實用的數位濾波器

ESP-DSP

FIR 濾波器的基本原理

FIR 濾波器的最大特點是其輸出僅依賴有限數量的輸入訊號點,這使得系統永遠穩定,且可以精確實現線性相位,避免相位失真。其運算本質是將輸入訊號的多個點乘以對應的係數後加總,產生新的輸出點。透過調整濾波器階數(使用多少輸入點)與係數設計,可以達到低通、高通、帶通等不同濾波效果

FIR 模組特色

ESP-DSP 是 Espressif 為 ESP32、ESP32-S3 等晶片打造的高性能數位信號處理庫,內含多種數學運算與濾波器實現,其中 FIR 模組支援浮點與定點運算,並且提供抽取(Decimation)功能,方便在不同應用中靈活使用

  • 結構化管理:利用結構體管理濾波器狀態,包括係數與延遲線,方便初始化與運算。
  • 優化實現:部分函數以匯編語言編寫,針對 ESP32 CPU 架構優化,確保運算效率與低功耗
  • 簡易調用:提供初始化與運算函數,使用者只需準備係數與延遲線,即可快速部署濾波器。

開發環境

在開始編程之前,請確保已完成以下準備工作:

專案結構

這是 ESP-IDF 預設的專案結構之一。當你使用 idf.py create-project 指令,或透過 VS Code 的官方 ESP-IDF 擴充套件建立新專案時,通常會看到這樣的配置:

esp32-fir-filter/
├── CMakeLists.txt
├── main/
│   ├── CMakeLists.txt
│   └── fir_filter_example.c
└── sdkconfig
  • CMakeLists.txt:專案的主建構設定檔。
  • main/:包含主要應用程式碼。
  • fir_filter_example.c:本範例的核心程式碼,實作 FIR 濾波器邏輯。
  • sdkconfig:由 menuconfig 自動產生的組態檔,記錄目前專案的配置設定。

這樣的架構讓我們開發起來更有條理,也方便未來維護或擴充。並符合 ESP-IDF 建議的開發方式。

程式實作

這個範例程式示範如何使用 ESP-DSP 函式庫來建立並應用一個 FIR(有限脈衝響應)數位濾波器,針對一個簡單的方波訊號進行平滑處理。
若需更精確的濾波效果,也可搭配 MATLAB、Python(SciPy)或 FIR filter designer 工具 設計更精緻的低通、高通、帶通或帶阻濾波器,並導出對應係數使用於本範例中。

#include <stdio.h>
#include "esp_log.h"
#include "esp_dsp.h"
#include "dsp_filter_fir.h"

#define FILTER_TAP_NUM 32
#define SIGNAL_LENGTH 128

// Define log tag for this module
static const char *TAG = "FIR_FILTER_EXAMPLE";

// Simplified low-pass filter coefficients (replace as needed)
float filter_coeffs[FILTER_TAP_NUM] = {
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125,
    0.03125, 0.03125, 0.03125, 0.03125
};

float input_signal[SIGNAL_LENGTH];
float output_signal[SIGNAL_LENGTH];
float delay_line[FILTER_TAP_NUM];

dsps_fir_t fir; // FIR filter structure

void app_main(void) {
    esp_err_t ret;

    ESP_LOGI(TAG, "ESP-DSP FIR filter example started");

    // Initialize FIR filter
    ret = dsps_fir_init_f32(&fir, filter_coeffs, delay_line, FILTER_TAP_NUM);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "FIR initialization failed");
        return;
    }

    // Generate square wave input signal
    for (int i = 0; i < SIGNAL_LENGTH; i++) {
        input_signal[i] = (i % 20 < 10) ? 1.0f : -1.0f;
    }

    // Apply FIR filter
    for (int i = 0; i < SIGNAL_LENGTH; i++) {
        output_signal[i] = dsps_fir_process_f32(&fir, input_signal[i]);
        ESP_LOGD(TAG, "Input: %.2f\tOutput: %.2f", input_signal[i], output_signal[i]);
    }

    ESP_LOGI(TAG, "Filtering completed");

    // Free FIR memory (optional)
    dsps_fir_free_f32(&fir);
}

程式說明 :

  • 定義濾波器參數與緩衝區
#define FILTER_TAP_NUM 32
#define SIGNAL_LENGTH 128
  1. FILTER_TAP_NUM:濾波器階數(Taps),即使用的係數數量。
  2. SIGNAL_LENGTH:模擬訊號長度,這裡是 128 筆資料點。
  • 初始化 FIR 濾波器
dsps_fir_init_f32(&fir, filter_coeffs, delay_line, FILTER_TAP_NUM);
  1. 使用 ESP-DSP 提供的函數初始化 fir 濾波器結構。
  2. filter_coeffs 是設計好的低通濾波器係數(此例為均值濾波器)。
  3. delay_line 是濾波器內部狀態的延遲線,需由使用者提供。
  • 產生輸入訊號(方波)
input_signal[i] = (i % 20 < 10) ? 1.0f : -1.0f;
  1. 模擬一個頻率固定的方波訊號:連續 10 筆為 +1.0,接著 10 筆為 -1.0,如此反覆。
  • 執行濾波運算
output_signal[i] = dsps_fir_process_f32(&fir, input_signal[i]);
  1. 將每筆輸入資料送入濾波器,計算對應輸出。
  2. 結果會逐步印出:「Input」與「Output」,方便觀察濾波效果。
  • 5. 清理資源(選擇性)
dsps_fir_free_f32(&fir);
  1. 雖然 ESP-DSP 的 FIR 實作通常不需要大量資源釋放,但為了良好習慣,這裡也示範釋放記憶體。

編譯和燒錄

完成程式碼後,您可以使用 ESP-IDF 提供的命令進行編譯、燒錄和監控。

在 VS Code 的左下角 ESP-IDF 工具列:

  • 點選 Build project
  • 點選 Flash device
  • 點選 Monitor device

輸出與測試結果

輸出數值會隨著 FIR 的累積卷積運算而逐漸「上升平滑」、「下降平滑」,這是典型低通濾波器處理效果。

I (0) FIR_FILTER_EXAMPLE: ESP-DSP FIR filter example started
D (10) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.03
D (20) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.06
D (30) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.09
D (40) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.13
D (50) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.16
...
D (310) FIR_FILTER_EXAMPLE: Input: -1.00	Output: 0.00
D (320) FIR_FILTER_EXAMPLE: Input: -1.00	Output: -0.03
D (330) FIR_FILTER_EXAMPLE: Input: -1.00	Output: -0.06
D (340) FIR_FILTER_EXAMPLE: Input: -1.00	Output: -0.09
...
D (800) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.00
D (810) FIR_FILTER_EXAMPLE: Input: 1.00	Output: 0.03
...
I (900) FIR_FILTER_EXAMPLE: Filtering completed

LOG 說明 :

  • 每一行 D (...)ESP_LOGD() 輸出的除錯訊息,顯示「原始輸入值」與「濾波後輸出值」。
  • 輸出數值會隨著 FIR 的累積卷積運算而逐漸「上升平滑」、「下降平滑」,這是典型低通濾波器處理效果。

結論

我們展示了如何運用 Espressif 的 ESP-DSP 函式庫,在 ESP32 上快速實作一個高效且穩定的 FIR 濾波器。透過簡單的初始化與逐點處理流程,即可針對輸入訊號進行即時濾波,實現如低通、平滑、降雜訊等效果。透過模擬的方波輸入,我們清楚觀察到 FIR 濾波器的平滑作用,有效去除尖銳變化與高頻成分,展現其在線性系統中的穩定性與實用性。

FIR 濾波器廣泛應用於各種場景,包括:

  1. 音訊處理
  2. 通訊系統
  3. 影像處理
  4. 感測器數據處理
  5. 工業與控制系統
  6. 嵌入式與 IoT 系統

透過這個實作,我們不僅掌握了 FIR 濾波的基本應用,也了解如何善用 ESP-DSP 提供的資源。未來你可以嘗試改變係數、改寫成帶通濾波器,甚至搭配 FFT 分析做更複雜的前處理流程。