Kalman Filtering in Embedded Systems: A Comprehensive Guide

We know that sensor signals can sometimes be interfered with, causing fluctuations in the data readout. To eliminate this interference, engineers utilize various filtering algorithms. Today, I will discuss Kalman filtering.

Part One: What is Kalman Filtering?

In simple terms, Kalman filtering is an efficient recursive filter that can estimate the optimal state of a dynamic system from a series of noisy measurement data.

You can think of it as an intelligent data fusion algorithm. It combines two pieces of information to provide a “best guess”:

  1. Prediction (based on the model): Based on the previous state of the system and known motion laws, it predicts what state the system should currently be in. However, this prediction has uncertainty.
  2. Measurement (from the sensor): It reads the current state of the system through the sensor. But this measurement also contains noise and errors.

The core idea of Kalman filtering is: When the prediction is accurate, trust the prediction more; when the measurement is accurate, trust the measurement more. It dynamically and automatically calculates whom to trust more through a set of mathematical formulas, ultimately obtaining a result that is much more accurate than simply using the prediction or the measurement alone.

A classic example: Estimating the position of a car

Suppose you are using a microcontroller to build a smart car and want to know its exact position.

  • Prediction: You know the last position and speed of the car. Based on the model “distance = speed × time,” you can predict where it should be now. But your model is not perfect (for example, due to ground slipping or wind resistance), so the prediction has errors.
  • Measurement: You use GPS to measure the current position of the car. However, the GPS signal has drift and noise, so the measurement is not entirely accurate.

Kalman filtering does the following:

  • If the GPS signal suddenly jumps (for example, from 1 meter to 10 meters away), but your model predicts the car has only moved 0.5 meters, the filter will consider “this measurement may not be very reliable,” and the final output position will lean more towards the predicted value, resulting in a smoother change.
  • If the GPS signal remains stable for a long time, the filter will gradually increase its trust in the measurement, and the output will closely follow the GPS.

The two core steps of Kalman filtering

  1. Prediction Step

  • Predict the current state based on the optimal estimate from the previous moment.
  • At the same time, the uncertainty of the prediction (covariance) will also increase because the prediction introduces new errors.
  • Update Step

    • Obtain the current sensor measurement value.
    • Compare the predicted value and the measurement value to calculate a weight called Kalman Gain.
    • Final optimal estimate = predicted value + Kalman Gain × (measurement value – predicted value)
    • This formula intuitively means “predicted value” plus a proportion of “the difference between the measurement value and the predicted value.” The Kalman Gain determines how large this proportion is.
    • Finally, update the uncertainty of the current state.

    This process repeats, with each new estimate based on the previous result, hence it is “recursive.”

    Part Two: Using Kalman Filtering in Microcontrollers

    Microcontrollers have limited resources (computational power, memory), so our goal is to implement a simplified, efficient, and sufficient Kalman filter.

    1. Choose the appropriate model: One-dimensional Kalman filtering

    For many microcontroller applications (such as filtering a temperature value or an angle value), we do not need to handle complex relationships between position and speed. We only care about one quantity, such as the temperature itself. In this case, we can use one-dimensional Kalman filtering, and the formulas are greatly simplified.

    Assuming the system model: We consider “the current temperature ≈ the previous temperature.” (This is the simplest model, where the state remains unchanged.) The sensor directly measures this temperature.

    The five core formulas are simplified as follows:

    Let:

    • <span>x</span>: optimal estimate (for example: optimal temperature)
    • <span>P</span>: estimated uncertainty (error covariance)
    • <span>z</span>: measurement value
    • <span>R</span>: measurement noise (for example: accuracy provided by the sensor manufacturer)
    • <span>Q</span>: process noise (the degree of imperfection of the model, usually a small adjustable parameter) initialization and loop execution
    float x = 0; // Initial estimate, e.g., the first measured temperaturefloat P = 1; // Initial uncertainty, can be set larger to indicate initial uncertaintyfloat R = 0.1; // Measurement noise, needs to be adjusted based on the sensor manual or testingfloat Q = 0.01; // Process noise, usually a small number that needs tuning
    // Prediction stepx = x;        // Simple model, predicted value is the last optimal valueP = P + Q;    // After prediction, uncertainty increases
    // Update stepfloat K = P / (P + R); // Calculate Kalman Gainx = x + K * (z - x);   // Update optimal estimateP = (1 - K) * P;       // Update uncertainty

    As you can see, in the one-dimensional case, the code is very concise and can easily run on an 8-bit microcontroller (such as the AVR in Arduino Uno).

    2. A bit more complex: Two-dimensional Kalman filtering (position + speed)

    If you need to estimate both position and speed simultaneously (for example, calculating speed and position based on an accelerometer), you will need two-dimensional Kalman filtering. The state variable <span>x</span> becomes a vector <span>[position, speed]'</span>, and <span>P</span>, <span>Q</span>, <span>R</span>, <span>K</span> all become matrices. The computational load will increase, but it can still be handled by 32-bit microcontrollers like STM32.

    Part Three: Steps and Tips for Implementation in Microcontrollers

    1. Modeling: Clarify your system. What do you want to estimate? (Angle, position?) What does your sensor measure? What is the motion model of the system? (Is it uniform motion? Or is the state basically unchanged?)

    2. Determine noise parameters (<span>Q</span> and <span>R</span>): This is key to tuning and directly affects filtering performance.

    • <span>R</span> (measurement noise): You can find accuracy indicators in the sensor data manual or approximate it by letting the sensor remain still and calculating the variance of the readings.
    • <span>Q</span> (process noise): Represents your level of trust in your model. The less accurate the model, the larger <span>Q</span> should be set. Usually, it is adjusted through experimentation:<span>Q</span> set large, the filter trusts the measurement more, responds quickly but with more noise; <span>Q</span> set small, the filter trusts the model more, output is smooth but responds slowly. A balance between “smoothness” and “response speed” needs to be struck.
  • Code Implementation:

    • Using floating-point calculations is the simplest, but some low-end microcontrollers have poor floating-point performance. If resources are tight, consider using fixed-point numbers to speed up calculations.
    • For matrix operations (two-dimensional and above), you can look for lightweight open-source libraries or write your own, being careful to avoid dynamic memory allocation.
  • Initial Values: The initial state <span>x</span> can be set to the first measurement value. The initial uncertainty <span>P</span> can be set larger so that the filter can quickly converge to the true value at the start.

  • A simple Arduino code example (one-dimensional filtering for smoothing analog readings)

    // One-dimensional Kalman filter parametersfloat x = 0; // Optimal estimatefloat P = 1; // Error covariancefloat R = 0.1; // Measurement noisefloat Q = 0.01; // Process noisevoid setup() {  Serial.begin(9600);  // Initialize state to the first reading  x = analogRead(A0);}void loop() {  // 1. Read measurement value  float z = analogRead(A0);  // 2. Prediction step  // x = x; // Model is constant, predicted value remains unchanged  P = P + Q;  // 3. Update step  float K = P / (P + R); // Kalman Gain  x = x + K * (z - x);  P = (1 - K) * P;  // Output raw value and filtered value  Serial.print(z);  Serial.print(",");  Serial.println(x);  delay(50);}

    Upload this code to Arduino, and use the serial plotter to observe that the original data jitter has been effectively smoothed.

    Conclusion

    • Advantages: Kalman filtering is an optimal estimation algorithm that effectively fuses model predictions and sensor information to obtain smooth and accurate results.
    • Key points for microcontroller implementation:
      • Start simple: Prioritize one-dimensional filtering.
      • Understand the model: Clarify your state variables and model.
      • Be patient with tuning: Adjusting <span>Q</span> and <span>R</span> is key and needs to be based on actual performance.
      • Focus on performance: On resource-constrained microcontrollers, pay attention to computational complexity and data types (fixed/float).

    I hope this explanation helps you understand and apply the powerful Kalman filtering in your microcontroller projects!

    Leave a Comment