# TinyEKF is a header-only Kalman filter with no dynamic memory

> TinyEKF is a single-header C and C++ implementation of the Extended Kalman Filter that avoids new and malloc entirely so it can run on an Arduino or an STM32, with a matching Python class for prototyping the filter before porting it. The author built it while writing a tutorial on the subject.

**simondlevy/TinyEKF** — Lightweight C/C++ Extended Kalman Filter with Python for prototyping

- Repository: https://github.com/simondlevy/TinyEKF
- Stars: 1,224 · Forks: 366
- Language: Python
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/simondlevy-tinyekf

## The constraint that shapes everything is no dynamic allocation

TinyEKF is a simple, header-only C/C++ implementation of the Extended Kalman Filter that is general enough to use on different projects, and the reason it is header-only is stated as a practical requirement rather than a style choice.

In order to make it practical for running on Arduino, STM32, and other microcontrollers, it uses static, compile-time memory allocation, with no new or malloc.

That single design decision explains most of the library's character. On a microcontroller with a few kilobytes of RAM, a filter that calls malloc on every update is not usable, because the allocation pattern of a filter is not predictable and fragmentation is a real failure mode. A filter with a fixed-size state vector and a fixed-size measurement vector has a memory footprint known at compile time, and it cannot fail at runtime for want of memory.

The implementation supports both single- and double-precision floating-point computation, which is the other half of the embedded story. A double-precision Kalman filter on an 8-bit AVR doubles the arithmetic cost and the state size, and for many sensor fusion problems on an Uno the single-precision version is the only one that fits the time budget.

The project comes from the author of a well known tutorial on the subject, linked from the README as the Extended Kalman Filter tutorial, so the library is the companion code to a piece of teaching material rather than a framework assembled from other libraries.

The repository layout is correspondingly small. There is a src/ directory holding the implementation, an examples/ directory with a GPS example and a SensorFusion example, a python/ directory, a library.properties file, an attic/ directory, a media/ directory for the images in the README, and a LICENSE.md.

## The Arduino example is a barometer and a thermometer

The examples folder contains both a pure C example from the literature and an Arduino example of sensor fusion, and the Arduino one is specific enough to be worth reading in detail.

It uses a BMP180 barometer and an LM35 linear temperature sensor, and the author says he has run this example on an Arduino Uno and a Teensy 3.2. The BMP180, being an I2C sensor, should be connected to pins 4 for SDA and 5 for SCL of the Uno, or pins 18 and 19 of the Teensy, and the analog output from the LM35 should go to the A0 pin.

The reason that example exists is worth understanding. A barometer measures pressure and a thermometer measures temperature, and the pressure reading depends on the altitude. So the filter is fusing two sensors to estimate altitude, which is exactly the problem the tutorial describes and exactly the problem where a Kalman filter earns its place. The barometer's altitude output drifts with the weather and the temperature correction has its own error, and fusing them produces a better altitude estimate than either alone.

That is the demonstration that the filter is general rather than a toy. The pure C example from the literature is the standard reference implementation, which is the right way to check that a filter is correct, since the published version has known results. The sensor fusion example is the one that shows it doing something on hardware.

The Teensy mention is also a signal about the range. A Teensy 3.2 is a 32-bit ARM Cortex-M4 board, and running the same example on an Uno, an 8-bit AVR with 2 KB of RAM, and a Teensy is a real constraint on the implementation. The static allocation and the single-precision option are what make the Uno possible.

The examples/SensorFusion folder also holds the Arduino sketch itself, the SensorFusion.ino file, and the README links to it directly with an image of the result.

## Prototype in Python, then port the same filter to C

The python/ folder is the part of the project that changes how you work, and the README is explicit about the workflow.

The python folder includes a Python class that you can use to prototype your EKF before implementing it in C or C++.

So the intended sequence is prototype in Python, then implement in C, and the C implementation is the one that ships to the device. That is a sensible division, because a filter has two hard parts and they fail differently. The maths is hard to get right and easy to iterate on, and the maths is the same in both languages. The part that is painful in Python is the performance and the memory, and that is exactly what the C version fixes.

The Python side has two examples of its own. One is a sensor fusion example, mirroring the Arduino one so the two can be compared. The other is a mouse tracking example using OpenCV, which the README says means you will have to install OpenCV to run it. Mouse tracking is a good demonstration for a different reason, because a mouse cursor position is a two dimensional state that is observed noisily and moves predictably, which is the textbook filter problem, and the visual output makes the filter's behaviour legible in a way a barometer reading does not.

The prototype-and-port approach has a well known failure mode, which is that the Python and C implementations drift, the Python one is the one you validate and the C one is the one that ships, and nobody checks that they agree. A library that ships both of them side by side, with the same filter in both languages, is at least set up so that a difference is visible, and the pure C example from the literature in the same repository gives a third point of comparison.

The README also mentions the pure C example is in the examples folder, and the two example folders at the top level are examples/GPS/ and examples/SensorFusion/, so the GPS example is the other well known filter problem, fusing a GPS position with something else to smooth the jumps.

## A library, not a framework, and an attic directory

There is an attic/ directory at the top of the repository, and it is a good sign rather than a bad one. An attic in a project like this usually means an older version of the code that has been kept for reference, either because someone still depends on it or because it documents a design that changed.

The library.properties file is the Arduino convention. It is the metadata file that tells the Arduino IDE what the library is called, which version it is, who the author is and which categories it belongs to, and it is what makes the drag-and-drop installation work. The README says Arduino users can simply install or drag the whole TinyEKF folder into their Arduino libraries folder, and the library.properties is the file that makes that folder a library rather than a collection of source files.

The src/ directory holding the implementation and the header-only claim together mean the Arduino drag-and-drop install works, because the Arduino build compiles every source file in the library folder, and a header-only library is a single file to include.

The licensing needs a note. The project listing marks the licence as a custom one that GitHub cannot classify, and there is a LICENSE.md at the root. For a library that someone is likely to copy into a firmware project, the terms of that file are the first thing to read, and the fact that it is not a standard SPDX identifier is worth a look rather than an assumption.

The project has no GitHub releases, and the last push to master was on 2026-04-09, more than six months before the current date. So the code is not being worked on this week, and there is no versioned artefact to pin. The trade for a user is the trade of any small library: a short, readable implementation you can read in an afternoon and adapt, with no guarantee that a change you would have wanted has landed.

## Where TinyEKF is the wrong choice

The first wrong case is a filter with a large or dynamic state. The whole design rests on the state vector and the measurement vector having a size known at compile time, so a filter whose dimension depends on the problem at hand, a number of tracked targets that grows, or a state that includes a variable number of landmarks, is outside what this code can express without edits.

The second wrong case is a team that wants a maintained filter library with a wide user base. There are well known extended Kalman filter packages for Python and for C++ with more features, matrix types, more numerical care around the covariance update and a community that has already found the edge cases. Choosing a small library means choosing to own the numerics.

The third wrong case is a problem where the model is linear. The extended Kalman filter linearises the measurement and process models around the current estimate, and for a problem where that is unnecessary, a plain Kalman filter is simpler, better conditioned and cheaper. Using the extended version because it is the one you found is a common and costly mistake.

The fourth wrong case is a project that needs a filter with non-Gaussian assumptions handled properly. An extended Kalman filter assumes the state error is approximately Gaussian and it linearises the propagation, so heavy-tailed measurement noise or a badly nonlinear model will make it confident and wrong. If that is your situation, an unscented or particle filter is the right tool, and this library is not.

## How it differs from a full filter library

The comparison worth making is with an established filter package, and the difference in approach is that this one is a teaching implementation and a building block rather than a product.

A general filter library gives you a matrix type, a filter object with configurable state and measurement dimensions at runtime, the various update methods, and a set of numerical utilities. It assumes a heap, a desktop, and a dependency tree. It comes with documentation covering the covariance conventions, the Joseph form versus the simplified update, and the tuning of the process noise.

TinyEKF gives you the algorithm, in a form you can read, with the sizes fixed at compile time and no dependencies. The reason to prefer that is not philosophical, it is that the algorithm is where the errors live. A filter with a wrong process noise, or a wrong ordering of the update steps, produces plausible but wrong results, and the only way to be confident is to understand the code and check it against a reference. The pure C example from the literature in the same repository is that reference, and the Python class gives you a second one to compare against.

The second difference is the deployment target. The Arduino and STM32 mention in the README is the whole reason for the static allocation. On a desktop, a filter that calls malloc is unremarkable. On an Uno with 2 KB of RAM, the difference between a static and a dynamic filter is the difference between running and not.

The third difference is the workflow it encourages. Because the Python class is the same filter as the C header, the recommended process is write it in Python where iteration is fast, then port it, and the C implementation is deliberately simple enough that a port is mechanical. A library that gave you everything in C would push the iteration cost onto the device, where it is highest.

The fourth difference is what you inherit. A full library has an issue tracker, a release history and a community. This one has a tutorial, an author, an attic directory and a last commit from April 2026. That is a perfectly good arrangement for a filter you will read once and adapt, and a poor one for a filter you will depend on for years.

## Conclusion

TinyEKF fits an embedded developer who needs an Extended Kalman Filter on a microcontroller with no heap and no build system, and it fits a robotics engineer who wants to prototype the filter in Python before porting it. It does not fit a project that needs matrix types beyond a fixed small size, and it does not fit a team that wants a maintained general purpose filter library with a large community behind it. Before adopting it, note that the design is deliberately minimal, that the licensing is a custom one GitHub cannot classify, and that the last push to master was on 2026-04-09 with no GitHub releases published.

## FAQ

### What is TinyEKF and why is it header-only?

It is a simple, header-only C and C++ implementation of the Extended Kalman Filter, general enough to use on different projects, supporting single and double precision. It is header-only and uses static compile-time memory allocation with no new or malloc, so it is practical on Arduino, STM32 and other microcontrollers.

### How do I use TinyEKF with an Arduino board?

Drag the whole TinyEKF folder into your Arduino libraries folder and the library.properties file makes it a recognised library. The SensorFusion example needs a BMP180 barometer on the I2C pins, 4 and 5 on an Uno or 18 and 19 on a Teensy, and an LM35 on the A0 pin, and the author has run it on an Arduino Uno and a Teensy 3.2.

### What is the Python part of TinyEKF for?

The python folder contains a Python class you can use to prototype your EKF before implementing it in C or C++. It includes a sensor fusion example mirroring the Arduino one and a mouse tracking example using OpenCV, which you need to install to run that one.

### Which examples does TinyEKF ship?

The examples folder holds both a pure C example from the literature, which is the reference to check a filter against, and an Arduino sensor fusion example. The top level example directories are examples/GPS/ and examples/SensorFusion/, and the SensorFusion folder also contains the SensorFusion.ino sketch itself.

### What license is TinyEKF released under?

The project listing marks the licence as a custom one that GitHub cannot classify, with a LICENSE.md file in the repository, so the terms in that file are what apply. The repository has no GitHub releases and the last push to master was on 2026-04-09.

## Sources

- [Issues](https://github.com/simondlevy/TinyEKF/issues)
- [README](https://github.com/simondlevy/TinyEKF/blob/master/README.md)
- [simondlevy/TinyEKF on GitHub](https://github.com/simondlevy/TinyEKF)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/simondlevy-tinyekf
