Lecture notes and notebooks must not be copied and/or distributed without the express permission of ITS.
The notebook is prepared by using the Chapters 1-6 of the Book "[Kalman and Bayesian Filters in Python](https://nbviewer.jupyter.org/github/rlabbe/Kalman-and-Bayesian-Filters-in-Python/blob/master/table_of_contents.ipynb)".
%% Cell type:code id: tags:
```
%pip install filterpy
```
%%%% Output: stream
Requirement already satisfied: filterpy in /usr/local/lib/python3.7/dist-packages (1.4.5)
Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from filterpy) (1.19.5)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from filterpy) (3.2.2)
Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from filterpy) (1.4.1)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->filterpy) (2.4.7)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->filterpy) (1.3.1)
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->filterpy) (2.8.1)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->filterpy) (0.10.0)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib->filterpy) (1.15.0)
%% Cell type:code id: tags:
```
#Fundamentals
import statistics
import numpy as np
from collections import namedtuple
import filterpy.stats as stats
from numpy.random import randn
from filterpy.stats import plot_gaussian_pdf, gaussian
from filterpy.common import Q_discrete_white_noise
#Data generation for Kalman filter:
from __future__ import (absolute_import, division, print_function, unicode_literals)
import copy
import math
#Plotting
import matplotlib as mpl
import plotly.graph_objects as go
import matplotlib.pylab as pylab
import matplotlib.pyplot as plt
```
%% Cell type:code id: tags:
```
import plotting as self_plots
```
%% Cell type:markdown id: tags:
# Alpha beta filter
You may have access the state of a given system via alternative sources: these could be different sensors attached on the system, a predictive model or simply your intuition (lets accept this a black box model) or you can measure the state of the system (lets say temperature) may times with one sensor (thermocouple). In a real world scenerio, non of these sources/measurements will be perfectly accurate, hence we need some sort of transformation fucntion correcting the our understanding of the system via available information.
Here our motiation is to use the available information fully, so we do not want to pick and rely on a relatively more accurate source, but try to use all our sources so as not to eliminate any insights about the state of the system we are interseted in.
Lets try to build our perspective starting with a simple exercise; temperature measurement.
Imagine that you are taking repeated measurement within a high pressure, high temperature chamber:
The result seems reasonable at first glance; the expected value falls in the middle of our observations. Yet there is a critical assumption here:
Our sensor is assumed to measure the same true temperature (say 390 C) as 380 and 400 with the same likelihood. Well, that is not usually the case, as we expect the sensor to read values closer to the true value most of the time and it should be less likely to print out a value as we get urther away from the true value.
Is the temperature increasing, decreasing or are we just seeing a noise? How many times I should measure before deciding a temperature value? It is definitely not practical to make 10k measurements to decide the state of the system! Can we use the trend in the data? Lets continue with temperature example:
It is clearly seen that mean approximation fails to capture the trend in the data, indicating a dynamical change in the state of the system. Maybe a better option could be some sort of trend fitting?
Here we have reached a bifurcation point: does my hypothesis reflect the true dynamics of the system? In other words, do I need to make additional measurements to further predict the state of the system or I am fine with the model (hypothesis) I have?
What we are interested here is a complex dynamical system, for which the state may evolve different than my current predictions. What we are after is a dynamical model, that can reflect the changes in the states I measure, different than my prior knowledge on the system. Therefore, we are going to use two sources of information (model and measurements) to update our understanding of the system (can you see the recurrent logic here as well?).
Lets imagine a case where we have start making new measurements and we have the model we have derived above. Our objective is to find a way to update our understanding of the system.
Lets return back to our example.
%% Cell type:code id: tags:
```
# Consider that we have recorded the following degrees with given delta_t:
prior estimation: 360.0 model prediction: 361.2 estimation: 359.4
prior estimation: 359.4 model prediction: 360.6 estimation: 363.2
prior estimation: 363.2 model prediction: 364.4 estimation: 362.0
prior estimation: 362.0 model prediction: 363.2 estimation: 360.9
prior estimation: 360.9 model prediction: 362.1 estimation: 362.5
prior estimation: 362.5 model prediction: 363.7 estimation: 364.0
prior estimation: 364.0 model prediction: 365.2 estimation: 368.1
prior estimation: 368.1 model prediction: 369.3 estimation: 368.3
prior estimation: 368.3 model prediction: 369.5 estimation: 367.5
prior estimation: 367.5 model prediction: 368.6 estimation: 370.3
prior estimation: 370.3 model prediction: 371.5 estimation: 371.4
prior estimation: 371.4 model prediction: 372.6 estimation: 372.7
%% Cell type:markdown id: tags:
Lets assume that our model roughly capture the true dynamics of the system (~ over-estimates). Lets see the impact of our filtering on the estimations:
%% Cell type:code id: tags:
```
true_data = []
[true_data.append(poly[0]*i*0.85 + 360.0) for i in range(len(temp_observations)+1)];
Our estimations are getting better as we move in time, which lies in between the measurements and the model predictions.
Since the current dynamics of the system is not that different than our model insight (in terms of the trends), we do an acceptable job. Question is, what happens when we enter a different regime, or shifting to a different equilibrium state?
Lets image that our model states that we are expecting a decrease in the temperature. Can measurements help us to correct this mistake?
%% Cell type:code id: tags:
```
#Calling our function:
initial_temp = 360.0
# note that we reverse the slope of the model to reflect the insight on decreasing temperatures:
This does not look so good. We can still make estimations that yield an increasing trend but the difference between the truth gets larger. In other words, if we just simple combine our prior understanding on the dynamics of the system with the measurements without updating our "view of the world", the filter will fail when there is change in the system behavior.
What could be the solution? Remember that we pass our prior knowledge in the form of a "gain", which was fixed based on our previous knowledge.
Here the trick is convert the gain parameter into a variable that is learning from our measurements and estimations.
%% Cell type:code id: tags:
```
# Lets rewrite our function:
#We need to define a learning rate for the gain update:
By comparing the measurements and our model predictions, we created a feedback information, which is then used to update our understanding of the system; that is the gain variable. Here we see that our estimations are much better than pure model predictions and learn the new dynamics in a few steps.
Note that we have some parameters here: learning_rate & scaling factor, which are chosen arbitrarily here. We could also use update the gain; take another model prediction; maybe avarage them and so on. The key idea here is to keep update our understanding of the system as new information becomes available.
%% Cell type:markdown id: tags:
## $\alpha$-$\beta$ filter
Above discussions and the algoithm we worked on id formally called $\alpha$-$\beta$ filter or g-h filter in the literature. There are many filter applications in the literature and they are, in one way or the other, interpretations of these two hyperparameters:
+ $\alpha$ is the scaling factor between the measurement and the prediction. If $\alpha$ is very small; we ignore the information coming from the measurements. If it is too large; we rely on the measurements too much hence reject very little of the noise (errors) in the measured values.
+ $\beta$ is the scaling factor between the measured residual and the model prediction, hence can be considered as a form of learning rate. A small $\beta$ value means we react to the changes in the landscape rather slowly.
For instance, in Kalman filter, $\alpha$-$\beta$ are varried dynamically at each time step, which we will see later.
%% Cell type:markdown id: tags:
### Using filterpy
%% Cell type:code id: tags:
```
# Creating a sensor readings for our simple filter:
When we increase $\alpha$ value, our estimates relies more on the measurement. If we look at the data, however, there are lots of noise so we should limit the influence of measurements.
We have seen that our understanding of the system and how we update this knowledge has a significant impact on the predictive accuracy of our filtering operation.
While building our knowledge towards Kalman filters, we will make a quick stop in Bayesian learning (If you would like to revise the concept, you may check Lecture 4 of DDE-I) and how we can use this strategy to update our understanding of the "world".
%% Cell type:markdown id: tags:
The beauty of the Bayesian approach is the way it interprets and updates the past knowledge (i.e. prior):