0
0
RosHow-ToBeginner · 4 min read

How to Implement FIR Filter on Microcontroller: Step-by-Step Guide

To implement a FIR filter on a microcontroller, store the filter coefficients and input samples in arrays, then compute the output by multiplying and summing these values in a loop. Use fixed-point or floating-point arithmetic depending on your microcontroller's capability for efficient processing.
📐

Syntax

The basic syntax for implementing a FIR filter involves storing the filter coefficients and input samples in arrays, then calculating the output sample by multiplying each coefficient with the corresponding input sample and summing all products.

Key parts:

  • coeffs[]: array of FIR filter coefficients
  • buffer[]: array holding recent input samples
  • output: the filtered output sample
  • Loop through coefficients and buffer to compute the sum of products
c
float fir_filter(float input, float *coeffs, float *buffer, int length) {
    // Shift buffer to make room for new input
    for (int i = length - 1; i > 0; i--) {
        buffer[i] = buffer[i - 1];
    }
    buffer[0] = input;

    float output = 0.0f;
    for (int i = 0; i < length; i++) {
        output += coeffs[i] * buffer[i];
    }
    return output;
}
💻

Example

This example shows a simple FIR filter implementation on a microcontroller using C. It applies a 5-tap FIR filter to a stream of input samples and prints the filtered output.

c
#include <stdio.h>

#define FILTER_TAPS 5

float fir_filter(float input, float *coeffs, float *buffer, int length) {
    for (int i = length - 1; i > 0; i--) {
        buffer[i] = buffer[i - 1];
    }
    buffer[0] = input;

    float output = 0.0f;
    for (int i = 0; i < length; i++) {
        output += coeffs[i] * buffer[i];
    }
    return output;
}

int main() {
    float coeffs[FILTER_TAPS] = {0.1f, 0.15f, 0.5f, 0.15f, 0.1f};
    float buffer[FILTER_TAPS] = {0};
    float inputs[10] = {1, 2, 3, 4, 5, 4, 3, 2, 1, 0};

    for (int i = 0; i < 10; i++) {
        float filtered = fir_filter(inputs[i], coeffs, buffer, FILTER_TAPS);
        printf("Input: %.2f, Filtered Output: %.4f\n", inputs[i], filtered);
    }
    return 0;
}
Output
Input: 1.00, Filtered Output: 0.1000 Input: 2.00, Filtered Output: 0.3500 Input: 3.00, Filtered Output: 1.1500 Input: 4.00, Filtered Output: 2.1500 Input: 5.00, Filtered Output: 3.1500 Input: 4.00, Filtered Output: 3.3500 Input: 3.00, Filtered Output: 3.1500 Input: 2.00, Filtered Output: 2.3500 Input: 1.00, Filtered Output: 1.3500 Input: 0.00, Filtered Output: 0.3500
⚠️

Common Pitfalls

Common mistakes when implementing FIR filters on microcontrollers include:

  • Not initializing the input buffer, causing garbage values in output.
  • Using floating-point arithmetic on microcontrollers without hardware support, leading to slow performance.
  • Forgetting to shift the input buffer before inserting new samples.
  • Incorrect coefficient ordering or length mismatch between coefficients and buffer.

Always verify buffer initialization and consider fixed-point math for low-power MCUs.

c
/* Wrong: Not shifting buffer before inserting new input */
float fir_filter_wrong(float input, float *coeffs, float *buffer, int length) {
    buffer[length - 1] = input; // Overwrites oldest sample
    float output = 0.0f;
    for (int i = 0; i < length; i++) {
        output += coeffs[i] * buffer[i];
    }
    return output;
}

/* Right: Shift buffer first, then insert new input */
float fir_filter_right(float input, float *coeffs, float *buffer, int length) {
    for (int i = length - 1; i > 0; i--) {
        buffer[i] = buffer[i - 1];
    }
    buffer[0] = input;
    float output = 0.0f;
    for (int i = 0; i < length; i++) {
        output += coeffs[i] * buffer[i];
    }
    return output;
}
📊

Quick Reference

  • Buffer size: Must match number of filter taps.
  • Coefficient order: Usually from newest to oldest sample.
  • Data type: Use fixed-point for performance on limited MCUs.
  • Initialization: Zero the buffer before filtering.
  • Optimization: Use DMA or hardware multiply-accumulate if available.

Key Takeaways

Store input samples in a buffer and shift it to insert new samples before filtering.
Multiply each input sample by its corresponding coefficient and sum all products to get the output.
Initialize buffers to zero to avoid garbage output at startup.
Use fixed-point arithmetic on microcontrollers without floating-point hardware for better speed.
Match the buffer size exactly to the number of filter coefficients (filter taps).