Got PDF book working.

Converted format of all notebooks so they can be processed with nbconvert.
Wrote a build_book script that merges the notebook and creates book.pdf
This commit is contained in:
Roger Labbe 2014-05-26 19:31:32 -07:00
parent b9f4dbe85e
commit 9c63574e80
19 changed files with 11738 additions and 1127 deletions

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:19fd5da8a72ab84659ebb5050018c8255375aa4b43f12f3bca2afe4505bd16c0"
"signature": "sha256:e2baeba25a3174dd9f44aa961606fbda4ef44c61e180085a8179c69f0e69bad4"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,10 +9,11 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"<h1 align=\"center\">Designing Kalman Filters</h1>"
"Designing Kalman Filters"
]
},
{
@ -251,23 +252,35 @@
"prompt_number": 2
},
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"#### Introduction\n",
"\n",
"In this chapter we will work through the design of several Kalman filters to gain experience and confidence with the various equations and techniques. \n",
"\n",
"For our first multidimensional problem we will track a robot in a 2D space, such as a field. We will start with a simple noisy sensor that outputs noisy $(x,y)$ coordinates which we will need to filter to generate a 2D track. Once we have mastered this concept, we will extend the problem significantly with more sensors and then adding control inputs. \n",
"blah blah\n"
"Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tracking a Robot\n",
"In this chapter we will work through the design of several Kalman filters to gain experience and confidence with the various equations and techniques. \n",
"\n",
"For our first multidimensional problem we will track a robot in a 2D space, such as a field. We will start with a simple noisy sensor that outputs noisy $(x,y)$ coordinates which we will need to filter to generate a 2D track. Once we have mastered this concept, we will extend the problem significantly with more sensors and then adding control inputs. \n",
"blah blah"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Tracking a Robot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This first attempt at tracking a robot will closely resemble the 1-D dog tracking problem of previous chapters. This will allow us to 'get our feet wet' with Kalman filtering. So, instead of a sensor that outputs position in a hallway, we now have a sensor that supplies a noisy measurement of position in a 2-D space, such as an open field. That is, at each time $T$ it will provide an $(x,y)$ coordinate pair specifying the measurement of the sensor's position in the field.\n",
"\n",
"Implemention of code to interact with real sensors is beyond the scope of this book, so as before we will program simple simuations in Python to represent the sensors. We will develop several of these sensors as we go, each with more complications, so as I program them I will just append a number to the function name. *pos_sensor1 ()* is the first sensor we write, and so on. \n",
@ -519,7 +532,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Step 6: Design the Process Noise Matrix\n",
"##### Step 6: Design the Process Noise Matrix\n",
"Finally, we design the process noise. We don't yet have a good way to model process noise, so for now we will assume there is a small amount of process noise, say 0.1 for each state variable. Later we will tackle this admittedly difficult topic in more detail. We have 4 state variables, so we need a $4{\\times}4$ covariance matrix:\n",
"\n",
"$$\\mathbf{Q} = \\begin{bmatrix}0.1&0&0&0\\\\0&0.1&0&0\\\\0&0&0.1&0\\\\0&0&0&0.1\\end{bmatrix}$$\n",
@ -554,7 +567,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### **Step 7**: Design Initial Conditions\n",
"##### **Step 7**: Design Initial Conditions\n",
"\n",
"For our simple problem we will set the initial position at (0,0) with a velocity of (0,0). Since that is a pure guess, we will set the covariance matrix $\\small\\mathbf{P}$ to a large value.\n",
"$$ \\mathbf{x} = \\begin{bmatrix}0\\\\0\\\\0\\\\0\\end{bmatrix}\\\\\n",
@ -594,11 +607,18 @@
],
"prompt_number": 9
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Implement the Filter Code"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Implement the Filter Code\n",
"Design is complete, now we just have to write the Python code to run our filter, and output the data in the format of our choice. To keep the code clear, let's just print a plot of the track. We will run the code for 30 iterations."
]
},
@ -834,12 +854,18 @@
"Finally, let's look at the lower left side of $\\small\\mathbf{P}$, which is all 0s. Why 0s? Consider $\\small\\mathbf{P}_{3,0}$. That stores the term $p\\sigma_3\\sigma_0$, which is the covariance between $\\dot{y}$ and $x$. These are independent, so the term will be 0. The rest of the terms are for similarly independent variables."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Realistic 2D Position Sensors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Realistic 2D Position Sensors\n",
"\n",
"The position sensor in the last example are not very realistic. In general there is no 'raw' sensor that provides (x,y) coordinates. We have GPS, but GPS already uses a Kalman filter to create a filtered output; we should not be able to improve the signal by passing it through another Kalman filter unless we incorporate additional sensors to provide additional information. We will tackle that problem later. \n",
"\n",
"Consider the following set up. In an open field we put two transmitters at a known location, each transmitting a signal that we can detect. We process the signal and determine how far we are from that signal, with some noise. First, let's look at a visual depiction of that."
@ -1148,12 +1174,18 @@
],
"prompt_number": 18
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Linearizing the Kalman Filter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Linearizing the Kalman Filter\n",
"\n",
"Now that we have seen an example of linearizing the Kalman filter we are in a position to better understand the math. \n",
"\n",
"We start by assuming some function $\\mathbf f$"

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:a427f15c81a2e5dc1b63cffe28b59aea4fde72a3894132dda51749ce2cdd6035"
"signature": "sha256:0ed2a79c9b9a5af478fd7349a380e31cad560037d74dc59e4deeb96893227198"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,10 +9,11 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"#Gaussian Probabilities"
"Gaussian Probabilities"
]
},
{
@ -62,7 +63,6 @@
" } \n",
" h2 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" text-indent:1em;\n",
" }\n",
" .text_cell_render h2 {\n",
" font-weight: 200;\n",
@ -242,20 +242,26 @@
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 8,
"prompt_number": 1,
"text": [
"<IPython.core.display.HTML at 0x435e510>"
"<IPython.core.display.HTML at 0x1080350>"
]
}
],
"prompt_number": 8
"prompt_number": 1
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Introduction\n",
"\n",
"The last chapter ended by discussing some of the drawbacks of the Discrete Bayesian filter. For many tracking and filtering problems our desire is to have a filter that is *unimodal* and *continuous*. That is, we want to model our system using floating point math (continuous) and to have only one belief represented (unimodal). For example, we want to say an aircraft is at (12.34381, -95.54321,2389.5) where that is latitude, longitude, and altidue. We do not want our filter to tell us \"it might be at (1,65,78) or at (34,656,98)\" That doesn't match our physical intuition of how the world works, and as we discussed, it is prohibitively expensive to compute.\n",
"\n",
">So we desire a unimodal, continuous way to represent probabilities that models how the real world works, and that is very computationally efficient to calculate. As you might guess from the chapter name, Gaussian distributions provide all of these features.\n",
@ -301,12 +307,18 @@
"<p>"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Nomenclature"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Nomenclature\n",
"\n",
"A bit of nomenclature before we continue - this chart depicts the probability of of a *random variable* having any value between ($-\\infty..\\infty)$. For example, for this chart the probability of the variable being 100 is roughly 2.7%, whereas the probability of it being 80 is around 1%.\n",
"> *Random variable* will be precisely defined later. For now just think of it as a variable that can 'freely' and 'randomly' vary. A dog's position in a hallway, air temperature, and a drone's height above the ground are all random variables. The position of the North Pole is not, nor is a sin wave (a sin wave is anything but 'free').\n",
"\n",
@ -315,12 +327,18 @@
"You will see these distributions called *Gaussian distributions*, *normal distributions*, and *bell curves*. Bell curve is ambiguous because there are other distributions which also look bell shaped but are not Gaussian distributions, so we will not use it further in this book. But *Gaussian* and *normal* both mean the same thing, and are used interchangeably. I will use both throughout this book as different sources will use either term, and so I want you to be used to seeing both. Finally, as in this paragraph, it is typical to shorten the name and just talk about a *Gaussian* or *normal* - these are both typical shortcut names for the *Gaussian distribution*. "
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Gaussian Distributions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Gaussian Distributions\n",
"\n",
"So let us explore how Gaussians work. A Gaussian is a *continuous probability distribution* that is completely described with two parameters, the mean ($\\mu$) and the variance ($\\sigma^2$). It is defined as:\n",
"$$ \n",
"f(x, \\mu, \\sigma) = \\frac{1}{\\sigma\\sqrt{2\\pi}} e^{-\\frac{1}{2}{(x-\\mu)^2}/\\sigma^2 }\n",
@ -388,9 +406,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"So what does this curve *mean*? Assume for a moment that we have a themometer, which reads 22$\\,^{\\circ}C$. No thermometer is perfectly accurate, and so we normally expect that thermometer will read $\\pm$ that temperature by some amount each time we read it. Furthermore, a theorem called **Central Limit Theorem** states that if we make many measurements that the measurements will be normally distributed. If that is true, then this chart can be interpreted as a continuous curve depicting our belief that the temperature is any given temperature. In this curve, we assign a probability of the temperature being exactly $22\\,^{\\circ}C$ is $19.95%$. Looking to the right, we assign the probability that the temperature is $24\\,^{\\circ}C$ is $12.10%$. Because of the curve's symmetry, the probability of $20\\,^{\\circ}C$ is also $12.10%$.\n",
"So what does this curve *mean*? Assume for a moment that we have a themometer, which reads 22$\\,^{\\circ}C$. No thermometer is perfectly accurate, and so we normally expect that thermometer will read $\\pm$ that temperature by some amount each time we read it. Furthermore, a theorem called **Central Limit Theorem** states that if we make many measurements that the measurements will be normally distributed. If that is true, then this chart can be interpreted as a continuous curve depicting our belief that the temperature is any given temperature. In this curve, we assign a probability of the temperature being exactly 22$^{\\circ}C$ is $19.95\\%$. Looking to the right, we assign the probability that the temperature is 24$^{\\circ}C$ is $12.10\\%$. Because of the curve's symmetry, the probability of 20$^{\\circ}$C is also $12.10\\%$.\n",
"\n",
"So the mean ($\\mu$) is what it sounds like - the average of all possible probabilities. Because of the symmetric shape of the curve it is also the tallest part of the curve. The thermometer reads $22\\,^{\\circ}C$, so that is what we used for the mean. \n",
"So the mean ($\\mu$) is what it sounds like - the average of all possible probabilities. Because of the symmetric shape of the curve it is also the tallest part of the curve. The thermometer reads $22^{\\circ}C$, so that is what we used for the mean. \n",
"\n",
"> *Important*: I will repeat what I wrote at the top of this section: \"A Gaussian...is completely described with two parameters\"\n",
"\n",
@ -441,7 +459,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"So what is this telling us? The blue gaussian is very narrow. It is saying that we believe $x=23$, and that we are very sure about that $(90%)$. In contrast, the red gaussian also believes that $x=23$, but we are much less sure about that $(18%)$. Our believe that $x=23$ is lower, and so our belief about the likely possible values for $x$ is spread out - we think it is quite likely that $x=20$ or $x=26$, for example. The blue gaussian has almost completely eliminated $22$ or $24$ as possible value - their probability is almost $0%$, whereas the red curve considers them nearly as likely as $23$.\n",
"So what is this telling us? The blue gaussian is very narrow. It is saying that we believe $x=23$, and that we are very sure about that $(90%)$. In contrast, the red gaussian also believes that $x=23$, but we are much less sure about that $(18%)$. Our believe that $x=23$ is lower, and so our belief about the likely possible values for $x$ is spread out - we think it is quite likely that $x=20$ or $x=26$, for example. The blue gaussian has almost completely eliminated $22$ or $24$ as possible value - their probability is almost $0\\%$, whereas the red curve considers them nearly as likely as $23$.\n",
"\n",
"If we think back to the thermometer, we can consider these three curves as representing the readings from three different thermometers. The blue curve represents a very accurate thermometer, and the red one represents a fairly inaccurate one. Green of course represents one in between the two others. Note the very powerful property the Gaussian distribution affords us - we can entirely represent both the reading and the error of a thermometer with only two numbers - the mean and the variance.\n",
"\n",
@ -487,12 +505,18 @@
"<div style=\"border:1px dotted black;background-color:#DCDCDC#\">**Sidebar**: An equivalent formation for a Gaussian is $\\mathcal{N}(\\mu,1/\\tau)$ where $\\mu$ is the *mean* and $tau$ the *precision*. Here $1/\\tau = \\sigma^2$; it is the reciprocal of the variance. While we do not use this formulation in this book, it underscores that the variance is a measure of how precise our data is. A small variance yields large precision - our measurement is very precise. Conversely, a large variance yields low precision - our belief is spread out across a large area. You should become comfortable with thinking about Gaussians in these equivelant forms. Gaussians reflect our *belief* about a measurement, they express the *precision* of the measurement, and they express how much *variance* there is in the measurements. These are all different ways of stating the same fact.</div>"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Interactive Gaussians"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Interactive Gaussians\n",
"\n",
"For those that are reading this in IPython Notebook, here is an interactive version of the Gaussian plots. Use the sliders to modify $\\mu$ and $\\sigma^2$. Adjusting $\\mu$ will move the graph to the left and right because you are adjusting the mean, and adjusting $\\sigma^2$ will make the bell curve thicker and thinner."
]
},
@ -535,12 +559,18 @@
],
"prompt_number": 7
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Computational Properties of the Gaussian"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Computational Properties of the Gaussian\n",
"\n",
"Recall how our discrete Bayesian filter worked. We had a vector implemented as a numpy array representing our belief at a certain moment in time. When we performed another measurement using the *sense()* function we had to multiply probabilities together, and when we performed the motion step using the *update()* function we had to shift and add probabilities. I've promised you that the Kalman filter uses essentially the same process, and that it uses Gaussians instead of histograms, so you might reasonable expect that we will be multipling, adding, and shifting Gaussians in the Kalman filter.\n",
"\n",
"A typical textbook would directly launch into a multipage proof of the behavior of Gaussians under these operations, but I don't see the value in that right now. I think the math will be much more intuitive and clear if we just start developing a Kalman filter using Gaussians. I will provide the equations for multiplying and shifting Gaussians at the appropriate time. You will then be able to develop a physical intuition for what these operations do, rather than be forced to digest a lot of fairly abstract math.\n",
@ -548,20 +578,25 @@
"The key point, which I will only assert for now, is that all the operations are very simple, and that they preserve the properties of the Gaussian. This is somewhat remarkable, in that the Gaussian is a nonlinear function, and typically if you multiply a nonlinear equation with itself you end up with a different equation. For example, the shape of $sin(x)sin(x)$ is very different from $sin(x)$. But the result of multiplying two Gaussians is yet another Gaussian. This is a fundamental property, and the key reason why Kalman filters are possible."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Summary and Key Points"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Summary and Key Points\n",
"\n",
"The following points **must** be understood by you before we continue:\n",
"\n",
"* Normal distributions occur throughout nature\n",
"* They express a continuous probability distribution\n",
"* They are completely described by two parameters: the mean ($\\mu$) and variance ($\\sigma^2$)\n",
"* $\\mu$ is the average of all possible values\n",
"* $\\sigma^2$ represents how much our measurements vary from the mean\n",
"\n"
"* $\\sigma^2$ represents how much our measurements vary from the mean"
]
}
],

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:43816bf77f55adc378d6365759a668c72b08dfb5d8cb7c26ce484ba0c3ee9571"
"signature": "sha256:184a4be9b0e4d6e3e2d860c8cea84921dd9917218e5400547215445113b16d1c"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,10 +9,11 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"#Kalman Filter Math"
"Kalman Filter Math"
]
},
{
@ -62,7 +63,6 @@
" } \n",
" h2 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" text-indent:1em;\n",
" }\n",
" .text_cell_render h2 {\n",
" font-weight: 200;\n",
@ -244,7 +244,7 @@
"output_type": "pyout",
"prompt_number": 1,
"text": [
"<IPython.core.display.HTML at 0x17ee690>"
"<IPython.core.display.HTML at 0x284b910>"
]
}
],
@ -259,30 +259,35 @@
"blah blah blah"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Walking Through the Kalman Filter Equations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"###Walking Through the Kalman Filter Equations\n",
"I promised that you would not have to understand how to derive Kalman filter equations, and that is true. However, I do think it is worth walking through the equations one by one and becoming familiar with the variables. If this is your first time through the material feel free to skip ahead to the next section. However, you will eventually want to work through this material, so why not now? You will need to have passing familarity with these equations to read material written about the Kalman filter, as they all presuppose that you are familiar with the equations. I will reiterate them here for easy reference.\n",
"\n",
"\n",
"$$\n",
"\\begin{align}\n",
"\\begin{aligned}\n",
"\\text{Predict Step}\\\\\n",
"\\mathbf{x}' &= \\mathbf{F x} + \\mathbf{B u}\\tag{1} \\\\\n",
"\\mathbf{P} &= \\mathbf{FP{F}}^T + \\mathbf{Q}\\tag{2} \\\\\n",
"\\mathbf{x}' &= \\mathbf{F x} + \\mathbf{B u}\\;\\;\\;\\;&(1) \\\\\n",
"\\mathbf{P} &= \\mathbf{FP{F}}^T + \\mathbf{Q}\\;\\;\\;\\;&(2) \\\\\n",
"\\\\\n",
"\\text{Update Step}\\\\\n",
"\\mathbf{\\gamma} &= \\mathbf{z} - \\mathbf{H x}\\tag{3} \\\\\n",
"\\mathbf{K}&= \\mathbf{PH}^T (\\mathbf{HPH}^T + \\mathbf{R})^{-1}\\tag{4} \\\\\n",
"\\mathbf{x}&=\\mathbf{x}' +\\mathbf{K\\gamma}\\tag{5} \\\\\n",
"\\mathbf{P}&= (\\mathbf{I}-\\mathbf{KH})\\mathbf{P}\\tag{6}\n",
"\\end{align}\n",
"\\mathbf{\\gamma} &= \\mathbf{z} - \\mathbf{H x}\\;\\;\\;\\;&(3) \\\\\n",
"\\mathbf{K}&= \\mathbf{PH}^T (\\mathbf{HPH}^T + \\mathbf{R})^{-1}\\;\\;\\;\\;&(4) \\\\\n",
"\\mathbf{x}&=\\mathbf{x}' +\\mathbf{K\\gamma}\\;\\;\\;\\;&(5) \\\\\n",
"\\mathbf{P}&= (\\mathbf{I}-\\mathbf{KH})\\mathbf{P}\\;\\;\\;\\;&(6)\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"\n",
"\n",
"I will start with the measurement step, as that is what we started with in the one dimensional Kalman filter case. Our first equation is\n",
"\n",
"$$\n",
@ -321,7 +326,7 @@
"\n",
"The next line is the formidable:\n",
"\n",
"$$\\mathbf{K}= \\mathbf{PH}^T (\\mathbf{HPH}^T + \\mathbf{R})^{-1}$$\n",
"$$\\mathbf{K}= \\mathbf{PH}^T (\\mathbf{HPH}^T + \\mathbf{R})^{-1}\\tag{4}$$\n",
"\n",
"Unfortunately it is a fair amount of linear algebra to derive this. The derivation can be quite elegant, and I urge you to look it up if you have the mathematical education to follow it. But $\\mathbf{K}$ is just the *Kalman gain* - the ratio of how much measurement vs prediction we should use to create the new estimate. $\\mathbf{R}$ is the *measurement noise*, and $\\mathbf{P}$ is our *uncertainty covariance matrix*.\n",
"\n",
@ -338,62 +343,45 @@
"\n",
"In other words, the *Kalman gain* equation is doing nothing more than computing a ratio based on how much we trust the prediction vs the measurement. If we are confident in our measurements and unconfident in our predictions $\\mathbf{K}$ will favor the measurement, and vice versa. The equation is complicated because we are doing this in multiple dimensions via matrices, but the concept is simple - scale by a ratio.\n",
"\n",
"Without going into the derivation of $\\mathbf{K}$, I'll say that this equation is the result of finding a value of $\\mathbf{K}$ that optimizes the *mean-square estimation error*. It does this by finding the minimal values for $\\mathbf{P}$ along it's diagonal. Recall that the diagonal of $P$ is just the variance for each state variable. So, this equation for $\\mathbf{K}$ ensures that the Kalman filter output is optimal. To put this in concrete terms, for our dog tracking problem this means that the estimates for both position and velocity will be optimal - a value of $\\mathbf{K}$ that made the position extremely accurate but the velocity very inaccurate would be rejected in favor of a $\\mathbf{K}$ that made both position and velocity just somewhat accurate.\n",
"\n",
"\n",
"Without going into the derivation of $\\mathbf{K}$, I'll say that this equation is the result of finding a value of $\\mathbf{K}$ that optimizes the *mean-square estimation error*. It does this by finding the minimal values for $\\mathbf{P}$ along it's diagonal. Recall that the diagonal of $P$ is just the variance for each state variable. So, this equation for $\\mathbf{K}$ ensures that the Kalman filter output is optimal. To put this in concrete terms, for our dog tracking problem this means that the estimates for both position and velocity will be optimal - a value of $\\mathbf{K}$ that made the position extremely accurate but the velocity very inaccurate would be rejected in favor of a $\\mathbf{K}$ that made both position and velocity just somewhat accurate."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Our next line is:\n",
" $$\\mathbf{x}=\\mathbf{x}' +\\mathbf{K\\gamma}$$\n",
" $$\\mathbf{x}=\\mathbf{x}' +\\mathbf{K\\gamma}\\tag{5}$$\n",
"\n",
"This just multiplies the residual by the Kalman gain, and adds it to the state variable. In other words, this is the computation of our new estimate.\n",
"\n",
"Finally, we have:\n",
"\n",
"$$\\mathbf{P}=(\\mathbf{I}-\\mathbf{KH})\\mathbf{P}$$\n",
"$$\\mathbf{P}=(\\mathbf{I}-\\mathbf{KH})\\mathbf{P}\\tag{6}$$\n",
"\n",
"$I$ is the identity matrix, and is the way we represent $1$ in multiple dimensions. $H$ is our measurement function, and is a constant. So, simplified, this is simply $P = (1-cK)P$. $K$ is our ratio of how much prediction vs measurement we use. So, if $K$ is large then $(1-cK)$ is small, and P will be made smaller than it was. If $K$ is small, then $(1-cK)$ is large, and P will be made larger than it was. So we adjust the size of our uncertainty by some factor of the *Kalman gain*. I would like to draw your attention back to the g-h filter, which included this Python code:\n",
"\n",
" # update filter \n",
" w = w * (1-scale_factor) + z * scale_factor\n",
"\n",
"This multidimensional Kalman filter equation is partially implementing this calculation for the variance instead of the state variable.\n",
"\n",
"This multidimensional Kalman filter equation is partially implementing this calculation for the variance instead of the state variable."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we have the measurement steps. The first equation is\n",
"\n",
"$$\\mathbf{x}' = \\mathbf{Fx} + \\mathbf{Bu}$$\n",
"$$\\mathbf{x}' = \\mathbf{Fx} + \\mathbf{Bu}\\tag{1}$$\n",
"\n",
"This is just our state transition equation which we have already discussed. $\\mathbf{Fx}$ multiplies $\\mathbf{x}$ with the state transition matrix to compute the next state. $B$ and $u$ add in the contribution of the control input $\\mathbf{u}$, if any.\n",
"\n",
"The final equation is:\n",
"$$\\mathbf{P} = \\mathbf{FPF}^T + \\mathbf{Q}$$\n",
"$$\\mathbf{P} = \\mathbf{FPF}^T + \\mathbf{Q}\\tag{2}$$\n",
"\n",
"$\\mathbf{FPF}^T$ is the way we put $\\mathbf{P}$ into the process space using linear algebra so that we can add in the process noise $\\mathbf{Q}$ to it."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 0
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 0
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:2d974c6ade3fc545dc4a52ec25342de94ed86181f0c1f6214bef7e63fff5b565"
"signature": "sha256:3b30412bf2631dd597e1e619df3837d5c18dcb65903323a2b7bc4a1c899a076a"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,10 +9,11 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"#Kalman Filters"
"Kalman Filters"
]
},
{
@ -62,7 +63,6 @@
" } \n",
" h2 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" text-indent:1em;\n",
" }\n",
" .text_cell_render h2 {\n",
" font-weight: 200;\n",
@ -244,26 +244,39 @@
"output_type": "pyout",
"prompt_number": 1,
"text": [
"<IPython.core.display.HTML at 0xe448d0>"
"<IPython.core.display.HTML at 0x10d8850>"
]
}
],
"prompt_number": 1
},
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"## One Dimensional Kalman Filters\n",
"Now that we understand the histogram filter and Gaussians we are prepared to implement a 1D Kalman filter. We will do this exactly as we did the histogram filter - rather than going into the theory we will just develop the code step by step. But first, let's set the book style."
"One Dimensional Kalman Filters"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we understand the histogram filter and Gaussians we are prepared to implement a 1D Kalman filter. We will do this exactly as we did the histogram filter - rather than going into the theory we will just develop the code step by step. But first, let's set the book style."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Tracking A Dog"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#Tracking A Dog\n",
"\n",
"As in the histogram chapter we will be tracking a dog in a long hallway at work. However, in our latest hackathon someone created an RFID tracker that provides a reasonable accurate position for our dog. Suppose the hallway is 100m long. The sensor returns the distance of the dog from the left end of the hallway. So, 23.4 would mean the dog is 23.4 meters from the left end of the hallway.\n",
"\n",
"Naturally, the sensor is not perfect. A reading of 23.4 could correspond to a real position of 23.7, or 23.0. However, it is very unlikely to correspond to a real position of say 47.6. Testing during the hackathon confirmed this result - the sensor is reasonably accurate, and while it had errors, the errors are small. Futhermore, the errors seemed to be evenly distributed on both sides of the measurement; a true position of 23m would be equally likely to be measured as 22.9 as 23.1.\n",
@ -480,13 +493,19 @@
"You may not have a full understanding of the exact *meaning* of a noise value of 100.0, but as it turns out if you multiply *randn()* with a number $n$, the result is just a normal distribution with $\\sigma = \\sqrt{n}$. So the example with noise = 100 is using the normal distribution $\\mathcal{N}(0,100)$. Recall the notation for a normal distribution is $\\mathcal{N}(\\mu,\\sigma^2)$. If the square root is confusing, recall that normal distributions use $\\sigma^2$ for the variance, and $\\sigma$ is the standard deviation, which we do not use in this book. DogSensor.<code><code>\\_\\_init__()</code> takes the square root of the noise setting so that the *noise &ast; randn()* call properly computes the normal distribution."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Math with Gaussians"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Math with Gaussians\n",
"\n",
"Let's say we believe that our dog is at 23m, and the variance is 5, or $pos_{dog}=\\mathcal{N}(23,5)$). We can represent that in a plot:\n"
"Let's say we believe that our dog is at 23m, and the variance is 5, or $pos_{dog}=\\mathcal{N}(23,5)$). We can represent that in a plot:"
]
},
{
@ -590,10 +609,10 @@
"\n",
"In other words the result is a Gaussian with \n",
"\n",
"$$\\begin{align*}\n",
"$$\\begin{aligned}\n",
"\\mu &=\\frac{\\sigma_1^2 \\mu_2 + \\sigma_2^2 \\mu_1} {\\sigma_1^2 + \\sigma_2^2}, \\\\\n",
"\\sigma &= \\frac{1}{\\frac{1}{\\sigma_1^2} + \\frac{1}{\\sigma_2^2}}\n",
"\\end{align*}$$"
"\\end{aligned}$$"
]
},
{
@ -765,32 +784,38 @@
"$\\sigma_1^2=0$, yielding\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"\\begin{aligned}\n",
"\\mu&=\\frac{0*\\mu_2 + \\sigma_2^2 \\mu_1} { \\sigma_2^2}, \\\\\n",
"\\text{or just}\\\\\n",
"\\mu&=\\mu_1\n",
"\\end{align*}\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"Finally, if we set $\\sigma_1^2 = 9\\sigma_2^2$, then the resulting equation is\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"\\begin{aligned}\n",
"\\mu&=\\frac{9 \\sigma_2^2 \\mu_2 + \\sigma_2^2 \\mu_1} {9 \\sigma_2^2 + \\sigma_2^2} \\\\\n",
"\\text{or just}\\\\\n",
"\\mu&= \\frac{1}{10} \\mu_1 + \\frac{9}{10} \\mu_2\n",
"\\end{align*}\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"This again fits our physical intuition of favoring the second, accurate scale over the first, inaccurate scale."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Implementing the Sensing Step"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Implementing the Sensing Step\n",
"\n",
"Recall the histogram filter uses a numpy array to encode our belief about the position of our dog at any time. That array stored our belief of our dog's position in the hallway using 10 discrete positions. This was very crude, because with a 100m hallway that corresponded to positions 10m apart. It would have been trivial to expand the number of positions to say 1,000, and that is what we would do if using it for a real problem. But the problem remains that the distribution is discrete and multimodal - it can express strong belief that the dog is in two positions at the same time.\n",
"\n",
"Therefore, we will use a single Gaussian to reflect our current belief of the dog's position. In other words, we will use $dog_{pos} = \\mathcal{N}(\\mu,\\sigma^2)$. Gaussians extend to infinity on both sides of the mean, so the single Gaussian will cover the entire hallway. They are unimodal, and seem to reflect the behavior of real-world sensors - most errors are small and clustered around the mean. Here is the entire implementation of the sense function for a Kalman filter:"
@ -892,12 +917,18 @@
"Mathematically it makes sense as well. Recall the computation for the variance after the multiplication: $\\sigma^2 = 1/(\\frac{1}{{\\sigma}_1} + \\frac{1}{{\\sigma}_2})$. We take the reciprocals of the sigma from the measurement and prior belief, add them, and take the reciprocal of the result. Think about that for a moment, and you will see that this will always result in smaller numbers as we proceed."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Implementing Updates"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"###Implementing Updates\n",
"\n",
"That is a beautiful result, but it is not yet a filter. We assumed that the dog was sitting still, an extremely dubious assumption. Certainly it is a useless one - who would need to write a filter to track nonmoving objects? The histogram used a loop of sense and update functions, and we must do the same to accomodate movement.\n",
"\n",
"How how do we perform the update function with gaussians? Recall the histogram method:\n",
@ -1187,12 +1218,18 @@
"> Before I go on, I want to emphasize that this code fully implements a 1D Kalman filter. If you have tried to read the literatue, you are perhaps surprised, because this looks nothing like the complex, endless pages of math in those books. To be fair, the math gets a bit more complicated in multiple dimensions, but not by much. So long as we worry about *using* the equations rather than *deriving* them we can create Kalman filters without a lot of effort. Moreover, I hope you'll agree that you have a decent intuitive grasp of what is happening. We represent our beliefs with Gaussians, and our beliefs get better over time because more measurement means more data to work with. \"Measure twice, cut once!\""
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Relationship to the g-h Filter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Relationship to the g-h Filter\n",
"\n",
"In the first chapter I stated that the Kalman filter is a form of g-h filter. However, we have been reasoning about the probability of Gaussians, and not used any of the reasoning or equations of the first chapter. A trivial amount of algebra will reveal the relationship, so let's do that now. It's not particularly illuminating algebra, so feel free to skip to the bottom to see the final equation that relates *g* to the variances.\n",
"\n",
"The equation for our estimate is:\n",
@ -1210,13 +1247,13 @@
"We can easily put this into the g-h form with the following algebra\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"\\begin{aligned}\n",
"\\mu_{x'}&=(x-x) + \\frac{ya + xb} {a+b} \\\\\n",
"\\mu_{x'}&=x-\\frac{a+b}{a+b}x + \\frac{ya + xb} {a+b} \\\\ \n",
"\\mu_{x'}&=x +\\frac{-x(a+b) + xb+ya}{a+b} \\\\\n",
"\\mu_{x'}&=x+ \\frac{-xa+ya}{a+b} \\\\\n",
"\\mu_{x'}&=x+ \\frac{a}{a+b}(y-x)\\\\\n",
"\\end{align*}\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"We are almost done, but recall that the variance of estimate is given by \n",
@ -1227,23 +1264,23 @@
"\n",
"We can incorporate that term into our equation above by observing that\n",
"$$ \n",
"\\begin{align*}\n",
"\\begin{aligned}\n",
"\\frac{a}{a+b} &= \\frac{a/a}{(a+b)/a} = \\frac{1}{(a+b)/a}\\\\\n",
" &= \\frac{1}{1 + \\frac{b}{a}} = \\frac{1}{\\frac{b}{b} + \\frac{b}{a}}\\\\\n",
" &= \\frac{1}{b}\\frac{1}{\\frac{1}{b} + \\frac{1}{a}} \\\\\n",
" &= \\frac{\\sigma^2_{x'}}{b}\n",
" \\end{align*}\n",
" \\end{aligned}\n",
"$$\n",
"\n",
"We can tie all of this together with\n",
"\n",
"$$\n",
"\\begin{align*}\n",
"\\begin{aligned}\n",
"\\mu_{x'}&=x+ \\frac{a}{a+b}(y-x)\\\\\n",
"&= x + \\frac{\\sigma^2_{x'}}{b}(y-x) \\\\\n",
"&= x + g_n(y-x)\\\\\n",
"\\blacksquare\n",
"\\end{align*}\n",
"\\end{aligned}\n",
"$$\n",
"\n",
"where\n",
@ -1273,11 +1310,18 @@
" sensor_error = 40 "
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Introduction to Designing a Filter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Introduction to Designing a Filter\n",
"So far we have developed our filter based on the dog sensors introduced in the Discrete Bayesian filter chapter. We are used to this problem by now, and may feel ill-equiped to implement a Kalman filter for a different problem. To be honest, there is still quite a bit of information missing from this presentation. The next chapter will fill in the gaps. Still, lets get a feel for it by designing and implementing a Kalman filter for a thermometer. The sensor for the thermometer outputs a voltage that corresponds to the temperature that is being measured. We have read the manufacturer's specifications for the sensor, and it tells us that the sensor exhibits white noise with a standard deviation of 2.13.\n",
"\n",
"We do not have a real sensor to read, so we will simulate the sensor with the following function. We have hard-coded the voltage to 16.3 - obviously the voltage will differ based on the temperature, but that is not important to our filter design."
@ -1450,12 +1494,18 @@
"The results do in fact look like a normal distribution. Each voltage is Gaussian, and the **Central Limit Theorem** guarantees that a large number of Gaussians is normally distributed. We will discuss this more in a subsequent math chapter."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Explaining the Results - Multi-Sensor Fusion"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"###Explaining the Results - Multi-Sensor Fusion\n",
"\n",
"So how does the Kalman filter do so well? I have glossed over one aspect of the filter as it becomes confusing to address too many points at the same time. We will return to the dog tracking problem. We used two sensors to track the dog - the RFID sensor that detects position, and the inertial tracker that tracked movement. However, we have focussed all of our attention on the position sensor. Let's change focus and see how the filter performs if the intertial tracker is also noisy. This will provide us with an vital insight into the performance of Kalman filters."
]
},
@ -1526,13 +1576,26 @@
"We will formalize this mathematically in the next chapter; for now trust this intuitive explanation. We use this sort of reasoning every day in our lives. If one person tells us something that seems far fetched we are inclined to doubt them. But if several people independently relay the same information we attach higher credence to the data. If one person disagrees with several other people, we tend to distrust the outlier. If we know the people that might alter our belief. If a friend is inclined to practical jokes and tall tales we may put very little trust in what they say. If one lawyer and three lay people opine on some fact of law, and the lawyer disagees with the three you'll probably lend more credence to what the lawyer says because of her expertise. In the next chapter we will learn how to mathematicall model this sort of reasoning."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"More examples"
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Example: Extreme Amounts of Noise"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### More examples\n",
"\n",
"##### Example: Extreme Amounts of Noise\n",
"So I didn't put a lot of noise in the signal, and I also 'correctly guessed' that the dog was at position 0. How does the filter perform in real world conditions? Let's explore and find out. I will start by injecting a lot of noise in the RFID sensor. I will inject an extreme amount of noise - noise that apparently swamps the actual measurement. What does your intution tell about how the filter will perform if the noise is allowed to be anywhere from -300 or 300. In other words, an actual position of 1.0 might be reported as 287.9, or -189.6, or any other number in that range. Think about it before you scroll down."
]
},
@ -1585,11 +1648,19 @@
"In this example the noise is extreme yet the filter still outputs a nearly straight line! This is an astonishing result! What do you think might be the cause of this performance? If you are not sure, don't worry, we will discuss it latter."
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Example: Bad Initial Estimate"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#####Example: Bad Initial Estimate\n",
"\n",
"Now let's lets look at the results when we make a bad initial estimate of position. To avoid obscuring the results I'll reduce the sensor variance to 30, but set the initial position to 1000m. Can the filter recover from a 1000m initial error?"
]
},
@ -1642,11 +1713,18 @@
"Again the answer is yes! Because we are relatively sure about our belief in the sensor ($\\sigma=30$) even after the first step we have changed our belief in the first position from 1000 to somewhere around 60.0 or so. After another 5-10 measurements we have converged to the correct value! So this is how we get around the chicken and egg problem of initial guesses. In practice we would probably just assign the first measurement from the sensor as the initial value, but you can see it doesn't matter much if we wildly guess at the initial conditions - the Kalman filter still converges very quickly."
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Example: Large Noise and Bad Initial Estimate"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#####Example: Large Noise and Bad Initial Estimate\n",
"What about the worst of both worlds, large noise and a bad initial estimate?"
]
},
@ -1753,11 +1831,18 @@
"200 iterations may seem like a lot, but the amount of noise we are injecting is truly huge. In the real world we use sensors like thermometers, laser rangefinders, GPS satellites, computer vision, and so on. None have the enormous error as shown here. A reasonable value for the variance for a cheap thermometer might be 10, for example, and our code is using 30,000 for the variance. "
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Exercise: Interactive Plots"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#####Exercise:\n",
"Implement the Kalman filter using IPython Notebook's animation features to allow you to modify the various constants in real time using sliders. Refer to the section **Interactive Gaussians** in the Gaussian chapter to see how to do this. You will use the *interact()* function to call a calculation and plotting function. Each parameter passed into *interact()* automatically gets a slider created for it. I have built the boilerplate for this; just fill in the required code."
]
},
@ -1855,15 +1940,21 @@
],
"prompt_number": 29
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Exercise - Nonlinear Systems"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#####Exercise - Nonlinear Systems\n",
"\n",
"Our equations are linear: \n",
"$$\\begin{align*}new\\_pos&=old\\_pos+dist\\_moved\\\\\n",
"new\\_position&=old\\_position*measurement\\end{align*}$$\n",
"$$\\begin{aligned}new\\_pos&=old\\_pos+dist\\_moved\\\\\n",
"new\\_position&=old\\_position*measurement\\end{aligned}$$\n",
"\n",
"Do you suppose that this filter works well or poorly with nonlinear systems?\n",
"\n",
@ -1942,9 +2033,21 @@
"Here we set a bad initial guess of 100. We can see that the filter never 'acquires' the signal. Note now the peak of the filter output always lags the peak of the signal by a small amount. More clearely we can see the large gap in height between the measurement and filter. \n",
"**REWriTE - not seeing heigh gap now**\n",
"\n",
"Maybe we just didn't adjust things 'quite right'. After all, the output looks like a sin wave, it is just offset in $x$ and $y$. Let's test this assumption.\n",
"\n",
"#####Exercise - Noisy Nonlinear Systems\n",
"Maybe we just didn't adjust things 'quite right'. After all, the output looks like a sin wave, it is just offset in $x$ and $y$. Let's test this assumption."
]
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Exercise - Noisy Nonlinear Systems"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Implement the same system, but add noise to the measurement."
]
},
@ -2017,11 +2120,18 @@
"Very shortly after practioners began implementing Kalman filters they realized the poor performance of them for nonlinear systems and began devising ways of dealing with it. Much of this book is devoted to this problem and its various solutions."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Summary"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Summary\n",
"This information in this chapter takes some time to assimulate. To truly understand this you will probably have to work through this chapter several times. I encourage you to change the various constants and observe the results. Convince yourself that Gaussians are a good representation of a unimodal belief of something like the position of a dog in a hallway. Then convince yourself that multiplying Gaussians truly does compute a new belief from your prior belief and the new measurement. Finally, convince yourself that if you are measuring movement, that adding the Gaussians correctly updates your belief. That is all the Kalman filter does. Even now I alternate between complacency and amazement at the results. \n",
"\n",
"If you understand this, you will be able to understand multidimensional Kalman filters and the various extensions that have been make on them. If you do not fully understand this, I strongly suggest rereading this chapter. Try implementing the filter from scratch, just by looking at the equations and reading the text. Change the constants. Maybe try to implement a different tracking problem, like tracking stock prices. Experimentation will build your intuition and understanding of how these marvelous filters work."

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:136798fb33e978117815e8cc04f4e7c4365f59442a30151e6a2f3e3d796c5e9f"
"signature": "sha256:0b133277ac85f975c916bc21148ad9bfba4634dc26c82d0842b53aee56e01439"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -17,11 +17,21 @@
"\n",
"### Version 0.0\n",
"\n",
"Not ready for public consumption. In development.\n",
"\n",
"\n",
"# Motivation\n",
"\n",
"Not ready for public consumption. In development."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Motivation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is a book for programmers that have a need or interest in Kalman filtering. The motivation for this book came out of my desire for a gentle introduction to Kalman filtering. I'm a software engineer that spent almost two decades in the avionics field, and so I have always been 'bumping elbows' with the Kalman filter, but never had the need to implement one myself. As I moved into solving tracking problems with computer vision I needed to start implementing them. There are classic textbooks in the field, such as Grewal and Andrew's excellent *Kalman Filtering*. But sitting down and trying to read these books is a dismal and trying experience if you do not have the background. Typcially the first few chapters fly through several years of undergraduate math, blithely referring you to textbooks on, for example, It\u014d calculus, and presenting an entire semester's worth of statistics in a few brief paragraphs. These books are good textbooks for an upper undergraduate course, and an invaluable reference to researchers and professionals, but the going is truly difficult for the more casual reader. Symbology is introduced without explanation, different texts use different words and variables names for the same concept, and the books are almost devoid of examples or worked problems. I often found myself able to parse the words and comprehend the mathematics of a defition, but had no idea as to what real world phenomena these words and math were attempting to describe. \"But what does that *mean?*\" was my repeated thought.\n",
"\n",
"However, as I began to finally understand the Kalman filter I realized the underlying concepts are quite straightforward. A few simple probability rules, some intuition about how we integrate disparate knowledge to explain events in our everyday life and the core concepts of the Kalman filter are accessible. Kalman filters have a reputation for difficulty, but shorn of much of the formal terminology the beauty of the subject and of their math became clear to me, and I fell in love with the topic. \n",
@ -37,13 +47,21 @@
"\n",
"This book has supporting libraries for computing statistics, plotting various things related to filters, and for the various filters that we cover. This does require a strong caveat; most code is written for didactic purposes. It is rare that I chose the most efficient solution (which often obscures the intent of the code), and I mostly did not concern myself with numerical stability. This is important to understand - Kalman filters in aircraft are carefully designed and implemented to be numerically stable; the naive implemention is not stable in many cases. If you are serious about Kalman filters this book will not be the last book you need. My intention is to introduce you to the concepts and mathematics, and to get you to the point where the textbooks are approachable.\n",
"\n",
"Finally, this book is free. The cost for the books required to learn Kalman filtering is somewhat prohibitive even for a Silicon Valley engineer like myself; I cannot believe the are within the reach of someone in a depressed economy, or a financially struggling student. I have gained so much from free software like Python, and free books like those from Allen B. Downey [here](http://www.greenteapress.com/). It's time to repay that. So, the book is free, it is hosted on free servers, and it uses free software for all of the code. \n",
"\n",
"\n",
"\n",
"\n",
"###Reading the book\n",
"\n",
"Finally, this book is free. The cost for the books required to learn Kalman filtering is somewhat prohibitive even for a Silicon Valley engineer like myself; I cannot believe the are within the reach of someone in a depressed economy, or a financially struggling student. I have gained so much from free software like Python, and free books like those from Allen B. Downey [here](http://www.greenteapress.com/). It's time to repay that. So, the book is free, it is hosted on free servers, and it uses free software for all of the code. "
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Reading the book"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are multiple ways to read this book. However, it is intended to be interactive and I recommend using it in that form. If you install IPython on your computer and then clone this book you will be able to run all of the code in the book yourself. You can perform experiments, see how filters react to different data, see how different filters react to the same data, and so on. I find this sort of immediate feedback both vital and invigorating. You do not have to wonder \"what happens if\". Try it and see!\n",
"\n",
"If you do not want to do that you can read this book online. the website http://nbviewer.org provides an IPython Notebook server that renders a notebook stored at github (or elsewhere). The rendering is done in real time when you load the book. If you read my book today, and then I make a change tomorrow, when you go back tomorrow you will see that change. \n",
@ -51,11 +69,21 @@
"You may access this book via nbviewer at any by using this address:\n",
"http://nbviewer.ipython.org/github/rlabbe/Kalman-Filters-and-Random-Signals-in-Python/blob/master/Introduction.ipynb\n",
"\n",
"Finally, you may generate output in a variety of formats. I will not cover how to do that, other than to point you to [IPython nbconvert](http://ipython.org/ipython-doc/rel-1.0.0/interactive/nbconvert.html). You can convert this book into static HTML pages, latex, or PDF. While I don't recommend it particularly, it is useful for those that don't want to program and/or are working offline.\n",
"\n",
"\n",
"###Installation and Software Requirements\n",
"\n",
"Finally, you may generate output in a variety of formats. I will not cover how to do that, other than to point you to [IPython nbconvert](http://ipython.org/ipython-doc/rel-1.0.0/interactive/nbconvert.html). You can convert this book into static HTML pages, latex, or PDF. While I don't recommend it particularly, it is useful for those that don't want to program and/or are working offline."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Installation and Software Requirements"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you want to run the notebook on your computer, which is what I recommend, then you will have to have IPython installed. I do not cover how to do that in this book; requirements change based on what other python installations you may have, whether you use a third party package like Anaconda Python, what operating system you are using, and so on. \n",
"\n",
"To use all features you will have to have Ipython 2.0 installed, which is released and stable as of April 2014. Most of the book does not require that, but I do make use of the interactive plotting widgets introduced in this release. A few cells will not run if you have an older version installed.\n",
@ -65,26 +93,51 @@
"You will need a recent version of NumPy, SciPy, and Matplotlib installed. I don't really know what the minimal might be. \n",
"I have numpy 1.71, SciPy 0.13.0, and Matplotlib 1.3.1 installed on my machines.\n",
"\n",
"Personally, I use the Anaconda Python distribution in all of my work, [available here](https://store.continuum.io/cshop/anaconda/). I am not selecting them out of favoritism, I am merely documenting my environment. Should you have trouble running any of the code, perhaps knowing this will help you.\n",
"\n",
"###Provided Libraries\n",
"\n",
"\n",
"Personally, I use the Anaconda Python distribution in all of my work, [available here](https://store.continuum.io/cshop/anaconda/). I am not selecting them out of favoritism, I am merely documenting my environment. Should you have trouble running any of the code, perhaps knowing this will help you."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Provided Libraries"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"I've not structured anything nicely yet. For now just look for any .py files in the base directory. As I pull everything together I will turn this into a python library, and probably create a separate git project just for the python code.\n",
"\n",
"There are python files with a name like *xxx*_internal.py. I use these to store functions that are useful for the book, but not of general interest. Often the Python is the point and focus of what I am talking about, but sometimes I just want to display a chart. IPython Notebook does not allow you to collapse the python code, and so it sometimes gets in the way. Some IPython books just incorporate .png files for the image, but I want to ensure that everything is open - if you want to look at the code you can. \n",
"\n",
"Some chapters introduce functions that are useful for the rest of the book. Those functions are initially defined within the Notebook itself, but the code is also stored in a Python file that is imported if needed in later chapters. I do document when I do this where the function is first defined. But this is still a work in progress.\n",
"Some chapters introduce functions that are useful for the rest of the book. Those functions are initially defined within the Notebook itself, but the code is also stored in a Python file that is imported if needed in later chapters. I do document when I do this where the function is first defined. But this is still a work in progress."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"License"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"http://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png\" /></a><br /><span xmlns:dct=\"http://purl.org/dc/terms/\" property=\"dct:title\">Kalman Filters and Random Signals in Python</span> by <a xmlns:cc=\"http://creativecommons.org/ns#\" href=\"https://github.com/rlabbe/Kalman-Filters-and-Random-Signals-in-Python\" property=\"cc:attributionName\" rel=\"cc:attributionURL\">Roger Labbe</a> is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.<br />\n",
"\n",
"\n",
"###License\n",
"\n",
"\n",
"<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"http://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png\" /></a><br /><span xmlns:dct=\"http://purl.org/dc/terms/\" property=\"dct:title\">Kalman Filters and Random Signals in Python</span> by <a xmlns:cc=\"http://creativecommons.org/ns#\" href=\"https://github.com/rlabbe/Kalman-Filters-and-Random-Signals-in-Python\" property=\"cc:attributionName\" rel=\"cc:attributionURL\">Roger Labbe</a> is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.<br />Based on a work at <a xmlns:dct=\"http://purl.org/dc/terms/\" href=\"https://github.com/rlabbe/Kalman-Filters-and-Random-Signals-in-Python\" rel=\"dct:source\">https://github.com/rlabbe/Kalman-Filters-and-Random-Signals-in-Python</a>.\n",
"\n",
"\n",
"###Contact\n",
"\n"
"Based on a work at <a xmlns:dct=\"http://purl.org/dc/terms/\" href=\"https://github.com/rlabbe/Kalman-Filters-and-Random-Signals-in-Python\" rel=\"dct:source\">https://github.com/rlabbe/Kalman-Filters-and-Random-Signals-in-Python</a>."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Contact"
]
},
{
@ -106,6 +159,10 @@
" margin-left: 0% !important;\n",
" margin-right: auto;\n",
" }\n",
" div.text_cell code {\n",
" background: #F6F6F9;\n",
" color: #0000FF;\n",
" }\n",
" h1 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
"\t}\n",
@ -127,7 +184,6 @@
" } \n",
" h2 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" text-indent:1em;\n",
" }\n",
" .text_cell_render h2 {\n",
" font-weight: 200;\n",
@ -199,7 +255,7 @@
" max-height: 300px;\n",
" }\n",
" code{\n",
" font-size: 78%;\n",
" font-size: 70%;\n",
" }\n",
" .rendered_html code{\n",
" background-color: transparent;\n",
@ -307,13 +363,13 @@
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 2,
"prompt_number": 1,
"text": [
"<IPython.core.display.HTML at 0x3f0ff50>"
"<IPython.core.display.HTML at 0x2c2e590>"
]
}
],
"prompt_number": 2
"prompt_number": 1
}
],
"metadata": {}

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:2b562cd882f0e19a9a7799763a6bf0d8986d23e7d0d648364928721d3c8a1026"
"signature": "sha256:b884811797e64562baf3c2f742fbb57d9857907b27eeb0885fa24fc3a524bb18"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,22 +9,246 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"<center><h1>Kalman and Bayesian Filters in Python</h1></center>\n",
"\n",
"<p>\n",
"<center><a href =\"http://nbviewer.ipython.org/urls/raw.github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python/master/toc.ipynb\">Table of Contents</a></center>"
"Signals and Noise"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"input": [
"#format the book\n",
"%matplotlib inline\n",
"from __future__ import division, print_function\n",
"import matplotlib.pyplot as plt\n",
"import book_format\n",
"book_format.load_style()"
],
"language": "python",
"metadata": {},
"outputs": []
"outputs": [
{
"html": [
"<style>\n",
" div.cell{\n",
" width: 850px;\n",
" margin-left: 0% !important;\n",
" margin-right: auto;\n",
" }\n",
" div.text_cell code {\n",
" background: #F6F6F9;\n",
" color: #0000FF;\n",
" }\n",
" h1 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
"\t}\n",
"\t\n",
" div.input_area {\n",
" background: #F6F6F9;\n",
" border: 1px solid #586e75;\n",
" }\n",
"\n",
" .text_cell_render h1 {\n",
" font-weight: 200;\n",
" font-size: 36pt;\n",
" line-height: 100%;\n",
" color:#c76c0c;\n",
" margin-bottom: 0.5em;\n",
" margin-top: 1em;\n",
" display: block;\n",
" white-space: wrap;\n",
" } \n",
" h2 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" }\n",
" .text_cell_render h2 {\n",
" font-weight: 200;\n",
" font-size: 20pt;\n",
" font-style: italic;\n",
" line-height: 100%;\n",
" color:#c76c0c;\n",
" margin-bottom: 1.5em;\n",
" margin-top: 0.5em;\n",
" display: block;\n",
" white-space: nowrap;\n",
" } \n",
" h3 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" }\n",
" .text_cell_render h3 {\n",
" font-weight: 300;\n",
" font-size: 18pt;\n",
" line-height: 100%;\n",
" color:#d77c0c;\n",
" margin-bottom: 0.5em;\n",
" margin-top: 2em;\n",
" display: block;\n",
" white-space: nowrap;\n",
" }\n",
" h4 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" }\n",
" .text_cell_render h4 {\n",
" font-weight: 300;\n",
" font-size: 16pt;\n",
" color:#d77c0c;\n",
" margin-bottom: 0.5em;\n",
" margin-top: 0.5em;\n",
" display: block;\n",
" white-space: nowrap;\n",
" }\n",
" h5 {\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" }\n",
" .text_cell_render h5 {\n",
" font-weight: 300;\n",
" font-style: normal;\n",
" color: #1d3b84;\n",
" font-size: 16pt;\n",
" margin-bottom: 0em;\n",
" margin-top: 1.5em;\n",
" display: block;\n",
" white-space: nowrap;\n",
" }\n",
" div.text_cell_render{\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" line-height: 135%;\n",
" font-size: 125%;\n",
" width:750px;\n",
" margin-left:auto;\n",
" margin-right:auto;\n",
" text-align:justify;\n",
" text-justify:inter-word;\n",
" }\n",
" div.output_subarea.output_text.output_pyout {\n",
" overflow-x: auto;\n",
" overflow-y: scroll;\n",
" max-height: 300px;\n",
" }\n",
" div.output_subarea.output_stream.output_stdout.output_text {\n",
" overflow-x: auto;\n",
" overflow-y: scroll;\n",
" max-height: 300px;\n",
" }\n",
" code{\n",
" font-size: 70%;\n",
" }\n",
" .rendered_html code{\n",
" background-color: transparent;\n",
" }\n",
" ul{\n",
" margin: 2em;\n",
" }\n",
" ul li{\n",
" padding-left: 0.5em; \n",
" margin-bottom: 0.5em; \n",
" margin-top: 0.5em; \n",
" }\n",
" ul li li{\n",
" padding-left: 0.2em; \n",
" margin-bottom: 0.2em; \n",
" margin-top: 0.2em; \n",
" }\n",
" ol{\n",
" margin: 2em;\n",
" }\n",
" ol li{\n",
" padding-left: 0.5em; \n",
" margin-bottom: 0.5em; \n",
" margin-top: 0.5em; \n",
" }\n",
" ul li{\n",
" padding-left: 0.5em; \n",
" margin-bottom: 0.5em; \n",
" margin-top: 0.2em; \n",
" }\n",
" a:link{\n",
" font-weight: bold;\n",
" color:#447adb;\n",
" }\n",
" a:visited{\n",
" font-weight: bold;\n",
" color: #1d3b84;\n",
" }\n",
" a:hover{\n",
" font-weight: bold;\n",
" color: #1d3b84;\n",
" }\n",
" a:focus{\n",
" font-weight: bold;\n",
" color:#447adb;\n",
" }\n",
" a:active{\n",
" font-weight: bold;\n",
" color:#447adb;\n",
" }\n",
" .rendered_html :link {\n",
" text-decoration: underline; \n",
" }\n",
" .rendered_html :hover {\n",
" text-decoration: none; \n",
" }\n",
" .rendered_html :visited {\n",
" text-decoration: none;\n",
" }\n",
" .rendered_html :focus {\n",
" text-decoration: none;\n",
" }\n",
" .rendered_html :active {\n",
" text-decoration: none;\n",
" }\n",
" .warning{\n",
" color: rgb( 240, 20, 20 )\n",
" } \n",
" hr {\n",
" color: #f3f3f3;\n",
" background-color: #f3f3f3;\n",
" height: 1px;\n",
" }\n",
" blockquote{\n",
" display:block;\n",
" background: #fcfcfc;\n",
" border-left: 5px solid #c76c0c;\n",
" font-family: 'Open sans',verdana,arial,sans-serif;\n",
" width:680px;\n",
" padding: 10px 10px 10px 10px;\n",
" text-align:justify;\n",
" text-justify:inter-word;\n",
" }\n",
" blockquote p {\n",
" margin-bottom: 0;\n",
" line-height: 125%;\n",
" font-size: 100%;\n",
" }\n",
"</style>\n",
"<script>\n",
" MathJax.Hub.Config({\n",
" TeX: {\n",
" extensions: [\"AMSmath.js\"]\n",
" },\n",
" tex2jax: {\n",
" inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ],\n",
" displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"] ]\n",
" },\n",
" displayAlign: 'center', // Change this to 'center' to center equations.\n",
" \"HTML-CSS\": {\n",
" styles: {'.MathJax_Display': {\"margin\": 4}}\n",
" }\n",
" });\n",
"</script>\n"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 1,
"text": [
"<IPython.core.display.HTML at 0x10e5990>"
]
}
],
"prompt_number": 1
}
],
"metadata": {}

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:5cac6d1e4e2cb015dbc3ae11ac0be80b8490b74c9ff0d054c006b499e2186165"
"signature": "sha256:5478490f2384cc166dd45368779e2c93fa7ab3ef0d0a4ef4c3f103c9c96f1a9a"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,10 +9,11 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"# Unscented Kalman Filters"
"Unscented Kalman Filters"
]
},
{

File diff suppressed because one or more lines are too long

10194
book.ipynb Normal file

File diff suppressed because one or more lines are too long

27
book.tplx Normal file
View File

@ -0,0 +1,27 @@
%((* extends 'report.tplx' *))
%===============================================================================
% Latex Book
%===============================================================================
((* block predoc *))
((( super() )))
((* block tableofcontents *))\tableofcontents((* endblock tableofcontents *))
((* endblock predoc *))
((* block title *))
\title{Kalman and Bayesian Filters in Python}
((* endblock title *))
% Define block headings
% Note: latex will only number headings that aren't starred
% (i.e. \subsection , but not \subsection* )
((* block h1 -*))\chapter((* endblock h1 -*))
((* block h2 -*))\section((* endblock h2 -*))
((* block h3 -*))\subsection((* endblock h3 -*))
((* block h4 -*))\subsubsection((* endblock h4 -*))
((* block h5 -*))\paragraph*((* endblock h5 -*))
((* block h6 -*))\subparagraph*((* endblock h6 -*))

22
build_book.bat Normal file
View File

@ -0,0 +1,22 @@
echo "merging book..."
python nbmerge.py Preface.ipynb Signals_and_Noise.ipynb g-h_filter.ipynb discrete_bayes.ipynb Gaussians.ipynb Kalman_Filters.ipynb Multidimensional_Kalman_Filters.ipynb Kalman_Filter_Math.ipynb Designing_Kalman_Filters.ipynb Extended_Kalman_Filters.ipynb Unscented_Kalman_Filter.ipynb > book.ipynb
echo "creating pdf..."
python nbconvert --to latex --template book --post PDF book.ipynb
mkdir output
copy /y *.tex output
copy /y *.pdf output
echo "done."

11
build_book.sh Executable file
View File

@ -0,0 +1,11 @@
#! /bin/bash
echo "merging book..."
ipython nbmerge.py Preface.ipynb Signals_and_Noise.ipynb g-h_filter.ipynb discrete_bayes.ipynb Gaussians.ipynb Kalman_Filters.ipynb Multidimensional_Kalman_Filters.ipynb Kalman_Filter_Math.ipynb Designing_Kalman_Filters.ipynb Extended_Kalman_Filters.ipynb Unscented_Kalman_Filter.ipynb > Kalman_and_Bayesian_Filters_in_Python.ipynb
echo "creating pdf..."
ipython nbconvert --to latex --template book --post PDF Kalman_and_Bayesian_Filters_in_Python.ipynb
echo "done."

5
clean_book.sh Executable file
View File

@ -0,0 +1,5 @@
#! /bin/bash
rm *.tex
rm *.toc
rm ./*_files/*.png
rmdir ./*_files/

View File

@ -1,7 +1,7 @@
{
"metadata": {
"name": "",
"signature": "sha256:21d9832d6077dac81c77a2069d45a9bbf83c85aa80ab3aa2a0df2870fec18787"
"signature": "sha256:1556bb7a2a15e47b34d1f079dab4a85d78afe50dc20aeb56325b4990232aeebd"
},
"nbformat": 3,
"nbformat_minor": 0,
@ -9,10 +9,11 @@
{
"cells": [
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"#Discrete Bayes Filter"
"Discrete Bayes Filter"
]
},
{
@ -254,15 +255,23 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The Kalman filter belongs to a family of filters called *bayesian filters*. Without going into"
"The Kalman filter belongs to a family of filters called *bayesian filters*. Without going into\n",
"\n",
"blah blah"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Tracking a Dog"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Tracking a Dog\n",
"\n",
"Let us begin with a simple problem. We have a dog friendly workspace, and so people bring their dogs to work. However, occasionally the dogs wander out of your office and down the halls. We want to be able to track them. So during a hackathon somebody created a little sonar sensor to attach to the dog's collar. It emits a signal, listens for the echo, and based on how quickly an echo comes back we can tell whether the dog is in front of an open doorway or not. It also senses when the dog walks, and reports in which direction the dog has moved. It connects to our network via wifi and sends an update once a second.\n",
"\n",
"I want to track my dog Simon, so I attach the device to his collar and then fire up Python, ready to try to write code to track him through the building. At first blush this may appear impossible. If I start listening to the sensor of Simon's collar I might read 'door', 'hall', 'hall', and so on. How can I use that information to determine where Simon is?\n",
@ -367,11 +376,18 @@
],
"prompt_number": 5
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Extracting Information from Multiple Sensor Readings"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Extracting Information from Multiple Sensor Readings\n",
"Let's put Python aside and think about the problem a bit. Suppose we were to read the following from Simon's sensor:\n",
"\n",
" * door\n",
@ -411,18 +427,25 @@
"We could work through the code to implement this solution, but instead let us consider a real world complication to the problem."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Noisy Sensors"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"####Noisy Sensors\n",
"Unfortunately I have yet to come across a perfect sensor. Perhaps the sensor would not detect a door if Simon sat in front of it while scratching himself, or it might report there is a door if he is facing towards the wall, not down the hallway. So in practice when I get a report 'door' I cannot assign 1/3 as the probability for each door. I have to assign something less than 1/3 to each door, and then assign a small probability to each blank wall position. At this point it doesn't matter exactly what numbers we assign; let us say that the probably of 'door' being correct is 0.6, and the probability of being incorrect is 0.2, which is another way of saying it is about 3 times more likely to be right than wrong. How would we do this?\n",
"\n",
"At first this may seem like an insurmountable problem. If the sensor is noisy it casts doubt on every piece of data. How can we conclude anything if we are always unsure?\n",
"\n",
"The key, as with the problem above, is probabilities. We are already comfortable with assigning a probabilistic belief about the location of the dog; now we just have to incorporate the additional uncertainty caused by the sensor noise. Say we think there is a 50% chance that our dog is in front of a specific door and we get a reading of 'door'. Well, we think that is only likely to be true 0.6 of the time, so we multiply: $0.5 * 0.6= 0.3$. Likewise, if we think the chances that our dog is in front of a wall is 0.1, and the reading is 'door', we would multiply the probability by the chances of a miss: $0.1 * 0.2 = 0.02$.\n",
"\n",
"However, we more or less chose 0.6 and 0.2 at random; if we multiply the pos array by these values the end result will no longer represent a true probability distribution. \n"
"However, we more or less chose 0.6 and 0.2 at random; if we multiply the pos array by these values the end result will no longer represent a true probability distribution. "
]
},
{
@ -516,12 +539,18 @@
"Normalization is done by dividing each element by the sum of all elements in the list. If this is not clear you should spend a few minutes proving it to yourself algebraically. We can see from the output that the sum is now 1.0, and that the probability of a door vs wall is still three times larger. The result also fits our intuitiion that the probability of a door must be less than 0.333, and that the probability of a wall must be greater than 0.0. Finally, it should fit our intuition that we have not yet been given any information that would allow us to distinguish between any given door or wall position, so all door positions should have the same value, and the same should be true for wall positions. "
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Incorporating Movement Data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Incorporating Movement Data\n",
"\n",
"Recall how quickly we were able to find an exact solution to our dog's position when we incorporated a series of measurements and movement updates. However, that occured in a fictional world of perfect sensors. Might we be able to find an exact solution even in the presense of noisy sensors?\n",
"\n",
"Unfortunately, the answer is no. Even if the sensor readings perfectly match an extremely complicated hallway map we could not say that we are 100% sure that the dog is in a specific position - there is, after all, the possibility that every sensor reading was wrong! Naturally, in a more typical situation most sensor readings will be correct, and we might be close to 100% sure of our answer, but never 100% sure. This may seem head-spinningly complicated, but lets just go ahead and program the math, which as we have seen is quite simple.\n",
@ -569,10 +598,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"We can see that we correctly shifted all values one position to the right, wrapping from the end of the array back to the beginning.\n",
"\n",
"#### Adding Noise to the Update\n",
"\n",
"We can see that we correctly shifted all values one position to the right, wrapping from the end of the array back to the beginning."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Adding Noise to the Update"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We want to solve real world problems, and we have already stated that all sensors have noise. Therefore the code above must be wrong. What if the sensor reported that our dog moved one space, but he actually moved two spaces, or zero? Once again this may initially sound like an insummountable problem, but let's just model it in math. Since this is just an example, we will create a pretty simple noise model for the sensor - later in the book we will handle far more sophisticated errors.\n",
"\n",
"We will say that when the sensor sends a movement update, it is 80% likely to be right, and it is 10% likely to overshoot one position to the right, and 10% likely to undershoot to the left. That is, if we say the movement was 4 (meaning 4 spaces to the right), the dog is 80% likely to have moved 4 spaces to the right, 10% to have moved 3 spaces, and 10% to have moved 5 spaces.\n",
@ -745,12 +785,18 @@
],
"prompt_number": 14
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Integrating Measurements and Movement Updates"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Integrating Measurements and Movement Updates\n",
"\n",
"The problem of loosing information during an update may make it seem as if our system would quickly devolve into no knowledge. However, recall that our process is not an endless series of updates, but of *measure->update->measure->update->measure->update...* The output of the measure step is fed into the update. The update step, with a degraded certainty, is then fed into the measure step. \n",
"\n",
"Let's think about this intuitively. After the first measure->update round we have degraded the knowledge we gained by the measurement by a small amount. But now we take another measurement. When we try to incorporate that new measurement into our belief, do we become more certain, less certain, or equally certain. Consider a simple case - you are sitting in your office. A co-worker asks another co-worker where you are, and they report \"in his office\". You keep sitting there while they ask and answer \"has he moved\"? \"No\" \"Where is he\" \"In his office\". Eventually you get up and move, and lets say the person didn't see you move. At that time the questions will go \"Has he moved\" \"no\" (but you have!) \"Where is he\" \"In the kitchen\". Wow! At that moment the statement that you haven't moved conflicts strongly with the next measurement that you are in the kitchen. If we were modelling these with probabilities the probability that you are in your office would lowever, and the probability that you are in the kitchen would go up a little bit. But now imagine the subsequent conversation: \"has he moved\" \"no\" \"where is he\" \"in the kitchen\". Pretty quickly the belief that you are in your office would fade away, and the belief that you are in the kitchen would increase to near certainty. The belief that you are in the office will never go to zero, nor will the belief that you are in the kitchen ever go to 1.0 because of the chances of error, but in practice your co-workers would be correct to be quite confident in their system.\n",
@ -897,12 +943,18 @@
"Here things have degraded a bit due to the long string of wall positions in the map. We cannot be as sure where we are when there is an undifferentiated line of wall positions, so naturally our probabilities spread out a bit."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"The Effect of Bad Sensor Data"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The Effect of Bad Sensor Data\n",
"\n",
"You may be suspicious of the results above because I always passed correct sensor data into the functions. However, we are claiming that this code implements a *filter* - it should filter out bad sensor measurements. Does it do that?\n",
"\n",
"To make this easy to program and visualize I will change the layout of the hallway to mostly alternating doors and hallways:"
@ -1012,12 +1064,18 @@
"As you can see we quickly filtered out the bad sensor reading and converged on the most likely positions for our dog."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Drawbacks and Limitations to the Discrete Bayesian Filter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Drawbacks and Limitations to the Discrete Bayesian Filter\n",
"\n",
"Do not be mislead by the simplicity of the examples I chose. This is a robust and complete implementation of a histogram filter, and you may use the code in real world solutions. If you need a multimodal, discrete filter, this filter works.\n",
"\n",
"With that said, while this filter is used in industry, it is not used often because it has several limitations. Getting around those limitations is the motivation behind the chapters in the rest of this book.\n",
@ -1063,19 +1121,30 @@
]
},
{
"cell_type": "markdown",
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"####Generalizing to Multiple Dimensions\n",
"\n"
"Generalizing to Multiple Dimensions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Summary"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Summary\n",
"\n",
"The code is very small, but the result is huge! We will go into the math more later, but we have implemented a form of a Bayesian filter. It is commonly called a Histogram filter. The Kalman filter is also a Bayesian filter, and uses this same logic to produce it's results. The math is a bit more complicated, but not by much. For now, we will just explain that Bayesian statistics compute the liklihood of the present based on the past. If we know there are two doors in a row, and the sensor reported two doors in a row, it is likely that we are positioned near those doors. Bayesian statistics just formalizes that example, and Bayesian filters formalize filtering data based on that math by implementing the sense->update->sense->update process. \n",
"\n",
"We have learned how to start with no information and derive information from noisy sensors. Even though our sensors are very noisey (most sensors are more then 80% accurate, for example) we quickly converge on the most likely position for our dog. We have learned how the update step always degrades our knowledge, but the addition of another measurement, even when it might have noise in it, improves our knowlege, allowing us to converge on the most likely result.\n",

File diff suppressed because one or more lines are too long

26
nbmerge.py Normal file
View File

@ -0,0 +1,26 @@
"""
usage:
python nbmerge.py A.ipynb B.ipynb C.ipynb > merged.ipynb
"""
import io
import os
import sys
from IPython.nbformat import current
def merge_notebooks(filenames):
merged = None
for fname in filenames:
with io.open(fname, 'r', encoding='utf-8') as f:
nb = current.read(f, 'json')
if merged is None:
merged = nb
else:
merged.worksheets[0].cells.extend(nb.worksheets[0].cells)
merged.metadata.name += "_merged"
print current.writes(merged, 'json')
if __name__ == '__main__':
merge_notebooks(sys.argv[1:])

View File

@ -29,7 +29,6 @@
}
h2 {
font-family: 'Open sans',verdana,arial,sans-serif;
text-indent:1em;
}
.text_cell_render h2 {
font-weight: 200;