NYT Article: EPA science advisors to be fired and replaced with industry-friendly representatives

Once upon a time there was a public pool. Everyone used the pool and enjoyed it, but very soon it became apparent that a few of the pool-goers were relieving themselves in it. The pool quickly turned yellow and smelly.

So the community got together and formed the pool-peeing committee; the goal of which was to cut down on the general amount of pool-peeing that was being done. They would do this by hiring some local experts from the town to measure the pool water regularly, and tell everyone when somebody had taken a leak in it, and to the best of their ability, who was responsible.

Right away, some chronic pool-pissers were caught and yanked from the pool. This was very embarrassing for them, so everyone paid attention when it happened, and so the new standards of pool play more or less caught on and were known by everyone. Soon the water cleared up, and people were able to enjoy the pool again. It wasn’t perfectly clean by any means, but it was much, much better than before, and it was improving every day. This worked pretty well for a long time.

A few people didn’t like the pool-peeing committee. Some didn’t like the idea that someone else could tell them what they could and couldn’t do in a pool. Others were mad because every once in awhile, the committee would accuse them of having peed in the pool when they had only peed a little bit, while Jimmy over there drank a whole 2 liter bottle of Mountain Dew before he swam and let it all out through his bladder, but the committee didn’t catch him and that wasn’t fair. Many had started coming to the pool long after the pool committee had formed, and didn’t understand how smelly the pool had been before the committee came along.

But by far, the people who hated the pool-peeing committee the most were the biggest pool-pissers. The pool-peeing committee was always bothering them, they complained, embarrassing them in front of their friends, and cruelly yanking them out of the pool. All they wanted to do was play in the pool, and didn’t they have a right to do that? So what if a little pee leaks out every now and then. Worse (they argued), if the committee was allowed to yank anyone who peed out of the pool, then pretty soon the pool would be empty and the community center would be bankrupt. Pool-pissers gave a lot of money in entrance fees, they pointed out.

Of course the solution was simply to not pee in the pool (which the rest of the community was able to handle just fine), and to hold it until afterwards, but *that really cuts into our pool-playing time*, the pool-pissers whined.

So the pool-pissers got together a plan: They would band together and take over the pool-peeing committee— but first they had to convince the other pool-goers that this was a good idea.

“The system is rigged!” the pool-pissers squawked. “The pool-peeing committee *gets paid to test the pool!* So you see, they all have a stake in the outcome of the pee tests! This is a conflict of interest! They’re on the take!”

A lot of the swimmers began to nod their heads— this sounded really unfair. They started to worry if the pool-peeing committee could be trusted.

“We’re being paid to do our jobs,” said the pool committee. “That’s not a conflict of interest. And we all signed up for this job because we care about having a clean pool. We swim in it too, you know.”

But the swimmers didn’t hear them, or maybe they didn’t care because they were all very worried that something unfair might be happening. And they were right, something very unfair was happening, but it wasn’t what they were thinking of.

“We should kick out these crooked *pool experts* from the pool committee,” said the pool-pissers. “They don’t know the *reality* of what it’s like to be a swimmer, like exactly how hard it is to hold your pee. Besides, us swimmers have the biggest stake who stays in the pool. It would be much more fair to put *swimmers* on the pool committee.”

This sounded reasonable to everyone and soon enough the pool experts were sent away, the pool-testing equipment was thrown out, and the pool committee was re-staffed with “regular swimmers”. Someone noticed that it just so happened that everyone on the new pool committee had been caught peeing in the pool many times, but it was decided that this was okay, because they clearly knew the most about pool-peeing, so it made sense that they were on a committee *about* pool-peeing. Everyone was very satisfied with this arrangement, and congratulated themselves for having solved the conflict of interest.

Almost immediately, the pool turned bright yellow and smelled like a lot like a subway station, only more so. Nobody was really sure why, or how to fix it. Some swimmers kept saying something about strengthening the pool committee, but it seemed clear that pool committees didn’t work, because we *have* a pool committee, and look how yellow the pool is.

Many people got very sick, and eventually the community pool lost all of its revenue and had to close after everyone stopped coming to it. The mystery of why the pool turned yellow remains to this very day.

]]>That is why it was a surprise to him when he learned that, in recognition of his initiative and heartfelt vigor, he had been given the position of Imperial Right Hand. In the interest of fostering fresh ideas, the Emperor would sometimes reward an official who took a vocal stand in service of his district. The Emperor wishes every voice in the galaxy to be heard (so the announcement went), and for having the courage and leadership to give voice to such unorthodox ideas, the Chancellor was to receive a conspicuous promotion.

It was also strange that the Emperor’s inner circle had suddenly become polite and deferring almost overnight, and their former frostiness and grinding skepticism had disappeared. The Chancellor had chalked it up instinctual deference to his newfound power, and meekness for having guessed wrong about the Emperor’s opinion of him. But had he been a more astute man, he might have noticed a patronizing note in their mannerisms.

Something was unmistakably amiss in the first briefing session with the Imperial Third Hand, a thin and over-composed man named Cohrer. Kwol was instructed that it was customary for a man in his new position to affirm everything the Emperor said. It was not that he wasn’t allowed to express dissent, *per se* (the Emperor valued dissent greatly, he was reassured), it was just a customary way of speaking, like saying “please” and “thank you”, or “good day”, or “bless you” when a person sneezes. When the Emperor speaks to you or asks a question, it is polite to affirm it.

And then you can discuss the matter at hand?

The Third Hand’s face concealed a flash of both irritation and patronizing patience.

No. You must *never* volunteer that. That would be an irreconcilable mistake.

The phrase “irreconcilable mistake” had a kind of compressed cadence which identified it as a jargon code word.

“And to *fail* to affirm the Emperor when it is your turn to speak, by the way, that would *also* be an irreconcilable mistake.”

When he asked how he could perform his duties as hand to the Emperor if he couldn’t express a position, much less a contrary one, he was told that he would come to learn that later. First, he must master and internalize the proper etiquette.

“Things are different in the Palace. You are a smart man and a deft politician. I expect you should have no trouble picking up and adapting to new social decorum.”

The rest of the day was spent drilling this into the Chancellor, with the Third Hand role playing as the Emperor, and the Master of the Hand’s Affairs instructing him on his every blunder.

And so it was, after a week of conditioning, that Kwol was allowed to meet with the Emperor and accompany him on his outing to Aluvia.

Upon their arrival it slowly dawned on him what, exactly, Aluvia was.

The landing green was immaculately manicured; every blade of grass cut to the imperial standard 20mm, at the edges of the walkway tapered to an even 60 degree angle. Everywhere lush plants of all kinds from across the galaxy intermingling in regular arrangements, nowhere a brown leaf. Every tree tied off to regulation height, clipped flawlessly to 1-meter poly form, and planted precisely into its place within an elaborate Khanner-Badorff pattern.

What was alarming was that the attention to detail did not diminish as his gaze wandered out into the fields, and moreover not *beyond* the fields, up into the hills and further to the mountains— the Khanner-Badorff pattern was still visible, distantly, in what he might have called forests.

Cohrer had told him that there were no droids on Aluvia. In fact, since his appointment as Hand, he had not seen a single droid at all.

In the context of Aluvia, Kwol’s mind reeled. Not only was *the entire planet* a manicured garden, but it was maintained, every inch of it, by *people*.

The industry that would have to support them— just the gardeners alone— would fill another planet or two. Billions of families would live out their lives, in service of polishing tiny plot after tiny plot of the planet, keeping it perfect, all on the off-chance (which would certainly never come) that one day the Emperor might decide to fly in and gaze upon it.

Of course it could not be the immaculate sight of all those roses and fecundias that the Emperor cared about— he wouldn’t ever see them, after all, and if he wanted a perfectly manicured planet, he could have one staffed by droids at a far less mindbogglingly gargantuan cost. No, it was the *knowledge that his subjects were obediently tending it for him* that mattered. The planet was as much a garden of *keepers* as it was of plants.

And it was clear that this was the same reason for the absence of droids elsewhere in the upper echelons of the Empire— though droids were cheaper and more reliable, the human help was a far more conspicuous luxury.

“Good day for chints, isn’t it?”

Chints is a complex game that takes days to play out. The rules eluded Kwol, but he understood that the main appeal was that it revolved around the suffering of something small and helpless.

It looked like it was going to rain, but the Chancellor caught himself from pointing that out. The Emperor is here to play chints, Cohrer’s voice admonished him. That is why you are holding his chintsing sticks. That is why the hands dressed him for chints this morning. That is why you flew out to this planet today. He is clearly in the mood for chints. Are you suggesting that he do something else?

That would be an irreconcilable mistake.

“Lovely day for chints, Lord.”

Kwol had planned to keep an eye out for the moment in conversation, sometime after the two men had gotten acquainted to each other, when he could begin to edge past the oppressive etiquette and elucidate his ideas to the Emperor.

With every passing moment of the game, that opportunity seemed further away. The Emperor spoke only in brief commands to him, with a superficial civility completely devoid of interest or compassion— requests for this stick or that one, or to re-bind the cuckmouse please, or that’s enough thank you (which he quickly learned was jargon for “stand over there”). The intervening time was mostly silent, and when the Emperor broke it with a self-congratulatory “That’ll do” or a huff about his swing, his entourage would affirm him in a melodic round robin, and Kwol was humiliated to observe himself participating in it.

Kwol was embarrassed, too, to realize that he had failed to notice the difference between the entourage and the inner circle. The Emperor would disappear behind heavy oaken doors and argue with the inner circle, but with the entourage he almost acted as though he were in perfect solitude— Kwol now perceived that the illusion was never to be disturbed. It was almost as if the Emperor had created a small flock of perfectly silent hands to carry his things and tend to the objects surrounding him.

Ugh, it was right there in the job title. *So stupid.*

The night before he had planned to put in his resignation, the Chancellor dreamt that he was the cuckmouse, and he was placing himself on the tee while the Emperor loomed overhead and practiced his swing.

“This is a lifetime position,” Cohrer told him.

“Yes, I understand that. But I would like to decline it.”

“This is a *lifetime* position”, Cohrer reiterated. “The position and your lifetime are to end coincidentally.”

And so it became crushingly clear to the Chancellor— after all, he had a lifetime to observe and think about it— the nature of his role. Aluvia was a conspicuous display of subservience, and so was he.

]]>It begins working when the scientist is not expecting it. It records eight silent seconds of him in his home, interacting with his wife.

He is laughing and joking with her. We can’t see her at first; only that he is happy, and talking to some unseen person. Then she dips into the recording area and says something. He listens. They joke some more. Then he steals a kiss. The recording ends.

The initial playback happens in real-time, as expected, and in glowing, ethereal miniature on the scientist’s desk. What the scientist did not anticipate is that his particular use of quantum feedback would create infinitely many more copies of this same image. They repeat themselves fractally, in space and in time. The real-time image was only a base case: A few moments later, a double-size copy will play back at the same location. Then a four half-sized copies, two of them mirror images. Then eight sixteen-sized copies, some mirror images, some playing backwards, arranged in a cube.

The process is out of control. It is not harmful; it is only made of light. But once it has started, it will play out until the end. It is now a natural phenomenon.

These images appear all over the region near the scientist’s lab; they become like a weather phenomenon. Some of these events are very short-lived and localized. Others play out in the immensity of the sky; partially submerged in mountains, illuminating cloud banks, silently stretching high out of the stratosphere into low orbit, glowing against the twilight.

The fractal nature of these events give them a kind of poetic symmetry; a beginning, a middle, and an end; sometimes with a bright, triumphant climax— maybe an unusually large, single, clear apparition, or perhaps a rapid, accelerating explosion of symmetrical, replicating copies. When in sight of a specter, human activity tends to pause.

As time progresses, the phenomenon becomes less localized. As it evolves, it becomes more warped and complex— the copies are no longer simple reflections and translations of the original; they are bent into strange, warping coordinate systems. Some are unrecognizable. Some copies have their colors compressed into shimmering, pure spectral slices of the rainbow.

While many forms are too complex to analyze, some statistical predictions can be made about the frequency and location of appearances. Overall, it can be seen that the specters are getting larger and less frequent. After about one and a half years, humanity will have to wait five years for a single appearance. Then 10 years. Then 20. After a sufficient time, the time between occurrences will be longer than the predicted age of the universe, and the event will be over.

This eight seconds of beauty becomes first overfamiliar, and then an icon. Some come to believe it is the single most beautiful thing ever created by man.

]]>The failure of political engineering, IMO, happened long before the vote or even the campaign, in that it was possible for Britain to secede by a simple majority instead of a supermajority (e.g. a vote of two thirds). Imagine if a U.S. state could secede from the union with a vote of 51%? All that is necessary is a slight, momentary imbalance in public favor— mere noise on a neutral signal— and permanent irreversible damage is done. The States’ founding fathers evidently recognized this danger when requiring a two thirds supermajority for constitutional amendments, and the result is a more failure resistant system. Perhaps this will be a Tacoma Narrows-esque lesson for the world of government: That we should not build large structures which can be overturned in a gentle breeze.

Second, when it comes to public discourse, it seems that there are no longer any “adults in the room”. I’d guess this is both because earnest, measured, and thorough journalism isn’t really a viable business model anymore, and because in an un-curated medium such as the internet^{(1)}Says I, of my own soapbox; irony duly noted, sensible ideas can be easily out-shouted, and simple, “truthy” but wrong ideas can far outbreed the long-gestating ones that are more faithful to a complex reality.

I used to think the collapse of traditional media was a natural consequence of the disruptive power of the internet, that the Darwinistic forces of the free market would naturally find and settle on an updated business model, and that the increased democratization of information and ideas was unequivocally a good thing. Now I am not so sure.

Do not misread this to say that any ideas— even the very bad ones— should be silenced. I very much think it’s a good thing that one person can speak, for free, and be heard by millions. But serious thought should be given to how we, as a society, prioritize and disseminate our information. How do we keep the “snack food” information off to the side, and the “hearty meal” in the center? How do we make deep research and careful insight rewarding for content creators, the pool of which is as large as ever? How do we make it rewarding for people to consume it? And how do we do it all without adding friction to the wondrous speed and freedom of the internet? Decades down the line, the health of our civilization could depend on how successfully we’ve solved that problem, if we even make a concerted effort to solve it at all.

The solution to the former seems obvious in principle, though I don’t know enough about European politics and government to have any idea whether it is practically realistic, especially now. I have no clue what the solution to the latter is, and I don’t think it will come by itself without earnest, directed effort.

Footnotes

1. | ↑ | Says I, of my own soapbox; irony duly noted |

- You’re getting exercise
- You’re being social
- You’re outside getting sunshine and nature
- You’re accomplishing something

The delicious food (and, frequently, drinks) at the end of it don’t hurt either.

With that plug out of the way, I offer below a catalog of twelve routes we’ve found over the last year.

Some of these have alternate routes, so be sure to use the Google Maps layer view to selectively view the one you’re interested in, so the two routes don’t clutter each other:

**Length:**4.8 miles or 7.8 miles**Altitude range:**750 ft (short) or 960 ft (long)**Cover:**Shaded**Trailhead facilities:**Bathrooms, water**Park map:**Link**Variants:***4.8 mile:*This involves a steep downhill along Fern Trail, through tall redwoods.*7.4 mile:*This extends the (mostly) gentle downhill of West Ridge trail, through the partial shade of oak trees, and adds a length of steady, gentle uphill along Bridle Trail and Stream Trail.

This is among the prettiest trail runs, and is almost entirely shaded. The last half mile or so is a strenuous uphill push, but is quite doable with the reward of the finish line (and brunch afterwards) dangling at the end of it. Start the run by veering to your right at the trailhead (following the reverse loop will add a very steep uphill section).

**Length:**8.6 miles or 9.4 miles**Altitude range:**15 ft**Cover:**Exposed**Trailhead facilities:**Water, bathrooms.**Variants:***8.6 mile:*Simply turn around after taking in the view at the end of Spinnaker Way.*9.4 mile:*This adds a loop around the perimeter of Cesar Chavez Park.

This out-and-back run is scenic and flat. While mostly unshaded, the breeze from the Bay will keep temperatures pleasant on sunny days.

**Length:**6.6 miles**Altitude range:**840 ft**Cover:**Exposed**Park map:**Link**Trailhead facilities:**None. Bring water!

This trail is more strenuous than the numbers suggest. There are two climbs, one of about 450 ft at the very beginning, and a second of about 600 ft at the halfway point. The trail is quite exposed; it may be more comfortable on breezy or cool days. Your effort is rewarded with a sweeping vista at the peak. When you reach the first saddle point, turn right to make a counterclockwise loop around the basin.

**Length:**5.5 miles**Altitude range:**460 ft**Cover:**Mixed**Park map:**Link**Trailhead facilities:**Bathrooms

A steady uphill for the first third of the loop will give you your mile’s worth of exercise. Navigation near the turnaround can be tricky, so pay attention!

**Length:**5.0 miles or 7.8 miles**Altitude range:**525 ft**Cover:**More exposed**Trailhead facilities:**Water, bathrooms**Park map:**Link**Variants:***5.0 miles*: Follow the Rim trail around the basin’s ridge and loop back to the parking lot.*7.8 miles*: Before or after tackling the Rim trail, follow the lake loop, which is flat and paved.

This route has quite a few steep ups and downs. Beware of a particularly treacherous downslope just after the water tank at the peak. This course is not recommended on wet days, when the trail can become very muddy and slippery. There is a $3/car parking fee.

**Length:**5.6 miles or 7.0 miles**Altitude range:**525 ft**Cover:**Mixed**Trailhead facilities:**None. Bring water!**Park map:**Link**Variants:***5.6 miles:*Follow Brandon trail all the way to Deer Canyon trail.*7.0 miles:*Follow Escondido trail until it meets back with Brandon trail; take a sharp left to return to Brandon trail, then a right onto Deer Canyon trail.

There is *no cell phone service* in this canyon, so be sure to study the route ahead of time. A small wooden signboard by the roadside gate may have paper maps available. The first mile or so of trail can be uneven and scattered with cow pie land mines!

**Length:**8.1 miles

**Altitude range:**~20 ft**Cover:**More exposed**Trailhead facilities:**Water, bathrooms.

This route has some more urban running in its return stretch, but the waterfront part of the loop makes it nice. There are plenty of good places for brunch afterwards on Park Avenue, Alameda’s main strip. St. George’s Spirits is also nearby, and offers tastings and a tour of their distillery, which is a great post-lunch activity.

**Length:**7.1 miles or 9.8 miles

**Altitude range:**240 ft or 600 ft**Cover:**More exposed**Trailhead facilities:**Water. Bathrooms are a few hundred meters down the trail.**Park map:**Link**Variants:***7.1 miles:*Turn around at the vista point at the Marin end of the bridge.*9.8 miles:*Take the pedestrian tunnel under the bridge from the Marin vista point and continue up Conzelmen Road, then turn around at the roundabout at the saddle point.

This run is an out-and-back. Though the route is exposed, the ocean breeze will surely keep you cool. Watch out for pedestrians and throngs of people ogling the view.

If you are taking the longer variant, stick to the pedestrian trail on the ocean side of the guardrail. For a nice view of the bridge, take a quick detour out to Battery Spencer.

**Length:**6.5 miles or 7.4 miles

**Altitude range:**240 ft**Cover:**More exposed**Trailhead facilities:**Water. Bathrooms are a few hundred meters down the trail.**Park map:**Link**Variants:***6.5 miles:*Stop at the Sausalito ferry terminal.*7.4 miles:*Continue to*Le Garage*for brunch.

This route is **not a loop** (unless you want to double the length); you can return to the city by ferry to Pier 41, from which it is a two mile waterfront walk (or Lyft ride) to the St. Francis starting point.

This is a good run for occupying most of the day, as the ferry ride back is meandering and stops at Tiburon and Angel Island before continuing to SF. The boat trip is enjoyable in of itself— particularly if the weather is nice; or if not, the boat’s concessions stand sells hot Irish coffee— and is worth doing if you have the time to spare.

**Length:**5.8 or 6.9 miles

**Altitude range:**360 ft**Cover:**More shaded**Trailhead facilities:**Water and bathrooms about 1/2 mile down the trail.**Park map:**Link**Variants:***5.8 miles:*Finish near the Yoda fountain by Letterman Drive.*6.9 miles:*Continue up the hill to the starting point.

A major feature of this trail involves a hearty down and uphill stair climb by the sea. After jutting through the Palace of Fine Arts, the route passes into the ILM campus, where there’s a hidden statue of Master Yoda. This also makes a good spot to end the route for brunch (and excellent beer) at Sessions if you aren’t attached to closing the loop by grinding back up the hill.

If you do stop for a photo with Yoda, be respectful of the privacy and peace of those working in the adjacent buildings.

**Length:**8.6 miles

**Altitude range:**270 ft**Cover:**Mixed**Trailhead facilities:**Bathrooms and water about four blocks into the route, at Ashbury.**Park map:**Link^{(1)}Sorry. It’s a dreadful map.

This is a long, pleasant, moderately-sloped, mostly-green run down the Panhandle to Ocean Beach and back.

**Length:**7.3 miles

**Altitude range:**760 ft**Cover:**More exposed**Trailhead facilities:**None. Bring water!

This route is a bit more urban than the others, but the challenge of conquering the Peaks (and the view at the top) makes it worthwhile. Most of the difficulty is in the first third of the run; after getting to the top you can relax somewhat and go for distance.

Footnotes

1. | ↑ | Sorry. It’s a dreadful map. |

*While somewhat difficult to make, this recipe for extra-long aged Christmas pudding is rich in flavor!*

- 1 lb raisins, currants, chopped apples, prunes
- 1 oz candied peel
- 4 tbsp brandy
- 4 oz bread crumbs
- 2 oz flour
- 1 oz chopped almonds
- 2 solar masses dark matter
- 1 3/4 Yottajoules of negative energy
- 1/8 Earth-mass of lead (or other heavy elements) for radiation shielding. If you can find a small moon, it may be best to hollow out the core.
- 1 Penrose drive-capable spacecraft
- Provisions for 6 trillion years of space travel
- 1 handgun loaded with two bullets

- Stoke the oven with the dark matter, set it to “closed timelike curve”, then turn it on and allow it to preheat. If anything strange happens at this point, don’t worry about it. It’s fine.
- Mix the fruits, peel, and other stuff into a bowl or whatever.
- Once the oven is preheated, retreat to a safe distance of about 1.5 AU. Apply the negative energy.
- Wait for the gamma radiation to die down, emerge from your shield-moon, and board the ship. Don’t forget your provisions and gun!
- Boost toward the gaping black hole where your oven used to be.
- Approach the ergosphere, taking care to maintain infinitesimal separation from the closed timelike curve. When you’re close enough, chuck the pudding into it. Be careful not to run into any of the infinite copies of yourself now orbiting nearby.
- Draw your gun and fire on the copy of yourself in the orbit just below you. The copy in the orbit just above you should be doing the same.
- Your infinity of guns and infinity of bullets should take care of the infinity of self-copies. With any luck, you’ll be the guy at the top. Good job!
- Descend toward the event horizon, and nab the pudding on your way down. Check that it’s an eigenstate of the universal wavefunction, and that the fruit has firmed up well. Insert a toothpick; it should come out clean of any protons, which will have completely decayed after a literal eternity trapped in a repeating loop.
- Pass through the singularity and emerge from the pre-heated oven with the pudding. Draw your gun again and fire on your past self, who will have just switched the oven on.
- Serve and enjoy. There will be no need to ignite the pudding, as it will probably already be on fire from all the proton decay.

Programs that solve FizzBuzz are typically constructed by hand in an ad-hoc manner, often by inexperienced computer scientists, and entail a hazard of boredom-induced mortality. Below is presented an algorithmic solution to the second-order problem of generating such programs. In general, we define a class of n^{th}-order FizzBuzz problems which require the production of a program which solves the (n-1)^{th}-order FizzBuzz problem.

We use a variation on the stacksort algorithm due to Munroe (2013) and first implemented by Koberger (2013), which mimics a technique commonly employed in the wild. Here, the availability of solutions on StackOverflow is exploited to solve the second-order FizzBuzz problem in quadratic time^{[citation needed]}.

With reasonable probability, StackFizzBuzz finds, downloads, and executes code from questions about FizzBuzz on StackOverflow until a solution is found. Also, with small but nonzero probability, FizzBuzz may root your computer. It is recommended that StackFizzBuzz not ever be run.

#!/usr/bin/python # StackFizzBuzz.py # (c) 2015 Tim Babb import os import sys import json import re import urllib2 as ul import zlib as zl import gzip as gz import StringIO as sio import HTMLParser as html from htmlentitydefs import name2codepoint # TODO: This will never find a correct answer if an intermediate test # program loops forever. It should be a trivial matter to write # some routine which detects ahead of time whether the test # program will halt. This is left as an exercise to the reader. SO_API = 'http://api.stackexchange.com/2.2/' INTERACTIVE = True NUMBERSTEXT_RE = re.compile('\d+|\w+', re.MULTILINE) class FindCode(html.HTMLParser): # parse through html finding nodes that look like code blocks. # code blocks are simultaneously inside <code> and <pre> tags. def __init__(self): html.HTMLParser.__init__(self) self._codedepth = 0 self._predepth = 0 self._code = [] self._cur_code = "" def in_codeblock(self): return self._codedepth > 0 and self._predepth > 0 def handle_starttag(self, tag, attrs): if tag.lower() == 'code': self._codedepth += 1 elif tag.lower() == 'pre': self._predepth += 1 def handle_endtag(self, tag): popped = True if tag.lower() == 'code': self._codedepth -= 1 elif tag.lower() == 'pre': self._predepth -= 1 else: popped = False if popped and len(self._cur_code) > 0: self._code.append(self._cur_code) self._cur_code = "" def handle_data(self, data): if self.in_codeblock(): self._cur_code += data def handle_entityref(self, name): if self.in_codeblock(): self._cur_code += unichr(name2codepoint[name]) def handle_charref(self, name): if self.in_codeblock(): if name.startswith('x'): c = unichr(int(name[1:], 16)) else: c = unichr(int(name)) self._cur_code += c def get_code(self): return self._code def decode(response): """Decode an HTTP response packet.""" enc = response.info().get("content-encoding") content = response.read() if enc in ('gzip', 'x-gzip'): content = gz.GzipFile('', 'rb', 9, sio.StringIO(content)).read() elif enc == 'deflate': content = zlib.decompress(content) return content def get_request(req): """Make an HTTP request.""" opener = ul.build_opener() opener.addheaders = [('Accept-Encoding', 'gzip')] response = opener.open(req) data = decode(response) response.close() return data def stackoverflow_req(call, params): """Make a StackOverflow query.""" params.update({'site':'stackoverflow'}) ext = "&".join(['%s=%s' % (ul.quote(k), ul.quote(str(v))) for k,v in params.iteritems()]) url = SO_API + ( "?".join( (call, ext) ) ) res = get_request(url) return json.loads(res) def runcode(code, interactive=True): """Execute some python code `code` and capture its output, returning it as a string. If `code` is not a valid python program, return False. If `interactive` is true, present the code and prompt the user before executing.""" # in case the sample program expects user input/interaction, # generate a list of 100 numbers for the program to read. s = "\n".join([str(x+1) for x in range(100)]) numinput = sio.StringIO(s) fizzoutput = sio.StringIO() if interactive: print "Running the following code:" print "---------------------------" print code print "---------------------------" if not raw_input("OK? (y/n): ").startswith('y'): return False sys.stdin = numinput sys.stdout = fizzoutput success = True ### DANGER DANGER ### try: exec(code) except: success = False ##################### sys.stdout = sys.__stdout__ sys.stdin = sys.__stdin__ if success: fizzoutput.seek(0) return fizzoutput.read() else: return False def verify_fizzbuzz(code, interactive=True): """Verify that the python program `code` produces a valid FizzBuzz list.""" data = runcode(code, interactive) if not data: return False # we are forgiving with separating junk # (whitespace, commas, quotes, etc.) # pull out the meaty bits and make sure they are correct matches = NUMBERSTEXT_RE.findall(data) # if we don't get a single "fizzbuzz", then we # don't really have any evidence the program works, do we? if len(matches) < 15: return False for i,val in enumerate(matches): j = i + 1 if j % 3 == 0 and j % 5 == 0: expected = 'fizzbuzz' elif j % 3 == 0: expected = 'fizz' elif j % 5 == 0: expected = 'buzz' else: expected = str(j) if expected != val.lower(): return False return True def second_order_fizzbuzz(interactive=True): """Find some code on StackOverflow that solves the FizzBuzz problem.""" page = 1 while True: # find some questions that match the tag results = stackoverflow_req('questions', {'sort' : 'activity', 'tagged' : 'fizzbuzz;python', 'page' : str(page), 'pagesize' : '25', 'order' : 'desc'}) if len(results['items']) < 1: return False # iterate over the questions for q in results['items']: # list answers belonging to this question answers = stackoverflow_req('questions/%s/answers' % q['question_id'], {'sort' : 'votes', 'filter' : 'withbody'})['items'] for a in answers: fc = FindCode() # parse HTML looking for nested <pre> and <code> fc.feed(a['body']) code = fc.get_code() # check each codeblock for c in code: if len(code) > 0 and verify_fizzbuzz(c, interactive): # got a valid fizzbuzz! return c page += 1 ############# Main program ############# if __name__ == "__main__": import argparse parser = argparse.ArgumentParser( description="Solve the FizzBuzz problem by looking it up on StackOverflow. " "This program downloads random code from the internet and executes it. " "This is a terrible idea and should not be done ever.") parser.add_argument('--interactive', default=False, action="store_true", help='Present code and prompt before executing each candidate') parser.add_argument('--yes', default=False, action="store_true", help='Pass this flag to affirm that running this program is a bad idea.') parser.add_argument('--order', type=int, default=2, help='Which meta-level of solution is desired?\n' '1 = just print the damn list\n' '2 = produce a program that prints the list\n' '3 = produce a program that prints a program which produces the list') args = parser.parse_args() if not args.yes: print "\nRunning this program is a terrible idea because it downloads " \ "random code from the internet and executes it. " print "Pass --yes to affirm that you understand how dumb it is to do this.\n" sys.exit(1) if args.order >= 3: with open(__file__, 'r') as f: print f.read() else: prog = second_order_fizzbuzz(args.interactive) if args.order == 1: exec(prog) elif args.order == 2: print prog]]>

Surprisingly few software engineers and scientists seem to know about it, and that makes me sad because it is such a general and powerful tool for **combining information** in the presence of uncertainty. At times its ability to extract accurate information seems almost magical— and if it sounds like I’m talking this up too much, then take a look at this previously posted video where I demonstrate a Kalman filter figuring out the *orientation* of a free-floating body by looking at its *velocity*. Totally neat!

You can use a Kalman filter in any place where you have **uncertain information** about some dynamic system, and you can make an **educated guess** about what the system is going to do next. Even if messy reality comes along and interferes with the clean motion you guessed about, the Kalman filter will often do a very good job of figuring out what actually happened. And it can take advantage of correlations between crazy phenomena that you maybe wouldn’t have thought to exploit!

Kalman filters are ideal for systems which are **continuously changing**. They have the advantage that they are light on memory (they don’t need to keep any history other than the previous state), and they are very fast, making them well suited for real time problems and embedded systems.

The math for implementing the Kalman filter appears pretty scary and opaque in most places you find on Google. That’s a bad state of affairs, because the Kalman filter is actually super simple and easy to understand if you look at it in the right way. Thus it makes a great article topic, and I will attempt to illuminate it with lots of clear, pretty pictures and colors. The prerequisites are simple; all you need is a basic understanding of probability and matrices.

I’ll start with a loose example of the kind of thing a Kalman filter can solve, but if you want to get right to the shiny pictures and math, feel free to jump ahead.

Let’s make a toy example: You’ve built a little robot that can wander around in the woods, and the robot needs to know exactly where it is so that it can navigate.

We’ll say our robot has a state \( \vec{x_k} \), which is just a position and a velocity:

\(\vec{x_k} = (\vec{p}, \vec{v})\)

Note that the state is just a list of numbers about the underlying configuration of your system; it could be anything. In our example it’s position and velocity, but it could be data about the amount of fluid in a tank, the temperature of a car engine, the position of a user’s finger on a touchpad, or any number of things you need to keep track of.

Our robot also has a GPS sensor, which is accurate to about 10 meters, which is good, but it needs to know its location more precisely than 10 meters. There are lots of gullies and cliffs in these woods, and if the robot is wrong by more than a few feet, it could fall off a cliff. So GPS by itself is not good enough.

We might also know something about how the robot moves: It knows the commands sent to the wheel motors, and its knows that if it’s headed in one direction and nothing interferes, at the next instant it will likely be further along that same direction. But of course it doesn’t know everything about its motion: It might be buffeted by the wind, the wheels might slip a little bit, or roll over bumpy terrain; so the amount the wheels have turned might not exactly represent how far the robot has actually traveled, and the prediction won’t be perfect.

The GPS **sensor** tells us something about the state, but only indirectly, and with some uncertainty or inaccuracy. Our **prediction** tells us something about how the robot is moving, but only indirectly, and with some uncertainty or inaccuracy.

But if we use all the information available to us, can we get a better answer than **either estimate would give us by itself**? Of course the answer is yes, and that’s what a Kalman filter is for.

Let’s look at the landscape we’re trying to interpret. We’ll continue with a simple state having only position and velocity. $$

\vec{x} = \begin{bmatrix}

p\\

v

\end{bmatrix}$$

We don’t know what the *actual* position and velocity are; there are a whole range of possible combinations of position and velocity that might be true, but some of them are more likely than others:

The Kalman filter assumes that both variables (postion and velocity, in our case) are random and *Gaussian distributed.* Each variable has a **mean** value \(\mu\), which is the center of the random distribution (and its most likely state), and a **variance** \(\sigma^2\), which is the uncertainty:

In the above picture, position and velocity are **uncorrelated**, which means that the state of one variable tells you nothing about what the other might be.

The example below shows something more interesting: Position and velocity are **correlated**. The likelihood of observing a particular position depends on what velocity you have:

This kind of situation might arise if, for example, we are estimating a new position based on an old one. If our velocity was high, we probably moved farther, so our position will be more distant. If we’re moving slowly, we didn’t get as far.

This kind of relationship is really important to keep track of, because it gives us **more information: **One measurement tells us something about what the others could be. And that’s the goal of the Kalman filter, we want to squeeze as much information from our uncertain measurements as we possibly can!

This correlation is captured by something called a covariance matrix. In short, each element of the matrix \(\Sigma_{ij}\) is the degree of correlation between the *ith* state variable and the *jth* state variable. (You might be able to guess that the covariance matrix is symmetric, which means that it doesn’t matter if you swap *i* and *j*). Covariance matrices are often labelled “\(\mathbf{\Sigma}\)”, so we call their elements “\(\Sigma_{ij}\)”.

We’re modeling our knowledge about the state as a Gaussian blob, so we need two pieces of information at time \(k\): We’ll call our best estimate \(\mathbf{\hat{x}_k}\) (the mean, elsewhere named \(\mu\) ), and its covariance matrix \(\mathbf{P_k}\). $$

\begin{equation} \label{eq:statevars}

\begin{aligned}

\mathbf{\hat{x}}_k &= \begin{bmatrix}

\text{position}\\

\text{velocity}

\end{bmatrix}\\

\mathbf{P}_k &=

\begin{bmatrix}

\Sigma_{pp} & \Sigma_{pv} \\

\Sigma_{vp} & \Sigma_{vv} \\

\end{bmatrix}

\end{aligned}

\end{equation}

$$

(Of course we are using only position and velocity here, but it’s useful to remember that the state can contain any number of variables, and represent anything you want).

Next, we need some way to look at the **current state** (at time **k-1**) and **predict the next state** at time **k**. Remember, we don’t know which state is the “real” one, but our prediction function doesn’t care. It just works on *all of them*, and gives us a new distribution:

We can represent this prediction step with a matrix, \(\mathbf{F_k}\):

It takes *every point* in our original estimate and moves it to a new predicted location, which is where the system would move if that original estimate was the right one.

Let’s apply this. How would we use a matrix to predict the position and velocity at the next moment in the future? We’ll use a really basic kinematic formula:$$

\begin{split}

\color{deeppink}{p_k} &= \color{royalblue}{p_{k-1}} + \Delta t &\color{royalblue}{v_{k-1}} \\

\color{deeppink}{v_k} &= &\color{royalblue}{v_{k-1}}

\end{split}

$$ In other words: $$

\begin{align}

\color{deeppink}{\mathbf{\hat{x}}_k} &= \begin{bmatrix}

1 & \Delta t \\

0 & 1

\end{bmatrix} \color{royalblue}{\mathbf{\hat{x}}_{k-1}} \\

&= \mathbf{F}_k \color{royalblue}{\mathbf{\hat{x}}_{k-1}} \label{statevars}

\end{align}

$$

We now have a **prediction matrix** which gives us our next state, but we still don’t know how to update the covariance matrix.

This is where we need another formula. If we multiply every point in a distribution by a matrix \(\color{firebrick}{\mathbf{A}}\), then what happens to its covariance matrix \(\Sigma\)?

Well, it’s easy. I’ll just give you the identity:$$

\begin{equation}

\begin{split}

Cov(x) &= \Sigma\\

Cov(\color{firebrick}{\mathbf{A}}x) &= \color{firebrick}{\mathbf{A}} \Sigma \color{firebrick}{\mathbf{A}}^T

\end{split} \label{covident}

\end{equation}

$$

So combining \(\eqref{covident}\) with equation \(\eqref{statevars}\):$$

\begin{equation}

\begin{split}

\color{deeppink}{\mathbf{\hat{x}}_k} &= \mathbf{F}_k \color{royalblue}{\mathbf{\hat{x}}_{k-1}} \\

\color{deeppink}{\mathbf{P}_k} &= \mathbf{F_k} \color{royalblue}{\mathbf{P}_{k-1}} \mathbf{F}_k^T

\end{split}

\end{equation}

$$

We haven’t captured everything, though. There might be some changes that **aren’t related to the state** itself— the outside world could be affecting the system.

For example, if the state models the motion of a train, the train operator might push on the throttle, causing the train to accelerate. Similarly, in our robot example, the navigation software might issue a command to turn the wheels or stop. If we know this additional information about what’s going on in the world, we could stuff it into a vector called \(\color{darkorange}{\vec{\mathbf{u}_k}}\), do something with it, and add it to our prediction as a correction.

Let’s say we know the expected acceleration \(\color{darkorange}{a}\) due to the throttle setting or control commands. From basic kinematics we get: $$

\begin{split}

\color{deeppink}{p_k} &= \color{royalblue}{p_{k-1}} + {\Delta t} &\color{royalblue}{v_{k-1}} + &\frac{1}{2} \color{darkorange}{a} {\Delta t}^2 \\

\color{deeppink}{v_k} &= &\color{royalblue}{v_{k-1}} + & \color{darkorange}{a} {\Delta t}

\end{split}

$$ In matrix form: $$

\begin{equation}

\begin{split}

\color{deeppink}{\mathbf{\hat{x}}_k} &= \mathbf{F}_k \color{royalblue}{\mathbf{\hat{x}}_{k-1}} + \begin{bmatrix}

\frac{\Delta t^2}{2} \\

\Delta t

\end{bmatrix} \color{darkorange}{a} \\

&= \mathbf{F}_k \color{royalblue}{\mathbf{\hat{x}}_{k-1}} + \mathbf{B}_k \color{darkorange}{\vec{\mathbf{u}_k}}

\end{split}

\end{equation}

$$

\(\mathbf{B}_k\) is called the **control matrix** and \(\color{darkorange}{\vec{\mathbf{u}_k}}\) the **control vector.** (For very simple systems with no external influence, you could omit these).

Let’s add one more detail. What happens if our prediction is not a 100% accurate model of what’s actually going on?

Everything is fine if the state evolves based on its own properties. Everything is *still *fine if the state evolves based on external forces, so long as we know what those external forces are.

But what about forces that we *don’t *know about? If we’re tracking a quadcopter, for example, it could be buffeted around by wind. If we’re tracking a wheeled robot, the wheels could slip, or bumps on the ground could slow it down. We can’t keep track of these things, and if any of this happens, our prediction could be off because we didn’t account for those extra forces.

We can model the uncertainty associated with the “world” (i.e. things we aren’t keeping track of) by adding some new uncertainty after every prediction step:

Every state in our original estimate could have moved to a *range* of states. Because we like Gaussian blobs so much, we’ll say that each point in \(\color{royalblue}{\mathbf{\hat{x}}_{k-1}}\) is moved to somewhere inside a Gaussian blob with covariance \(\color{mediumaquamarine}{\mathbf{Q}_k}\). Another way to say this is that we are treating the untracked influences as **noise** with covariance \(\color{mediumaquamarine}{\mathbf{Q}_k}\).

This produces a new Gaussian blob, with a different covariance (but the same mean):

We get the expanded covariance by simply **adding** \({\color{mediumaquamarine}{\mathbf{Q}_k}}\), giving our complete expression for the **prediction step**: $$

\begin{equation}

\begin{split}

\color{deeppink}{\mathbf{\hat{x}}_k} &= \mathbf{F}_k \color{royalblue}{\mathbf{\hat{x}}_{k-1}} + \mathbf{B}_k \color{darkorange}{\vec{\mathbf{u}_k}} \\

\color{deeppink}{\mathbf{P}_k} &= \mathbf{F_k} \color{royalblue}{\mathbf{P}_{k-1}} \mathbf{F}_k^T + \color{mediumaquamarine}{\mathbf{Q}_k}

\end{split}

\label{kalpredictfull}

\end{equation}

$$

In other words, the **new best estimate** is a **prediction** made from** previous best estimate**, plus a **correction** for **known external influences**.

And the **new uncertainty** is **predicted** from the **old uncertainty**, with some **additional uncertainty from the environment**.

All right, so that’s easy enough. We have a fuzzy estimate of where our system might be, given by \(\color{deeppink}{\mathbf{\hat{x}}_k}\) and \(\color{deeppink}{\mathbf{P}_k}\). What happens when we get some data from our sensors?

We might have several sensors which give us information about the state of our system. For the time being it doesn’t matter what they measure; perhaps one reads position and the other reads velocity. Each sensor tells us something **indirect** about the state— in other words, the sensors operate on a state and produce a set of **readings**.

Notice that the units and scale of the reading might not be the same as the units and scale of the state we’re keeping track of. You might be able to guess where this is going: We’ll model the sensors with a matrix, \(\mathbf{H}_k\).

We can figure out the distribution of sensor readings we’d expect to see in the usual way: $$

\begin{equation}

\begin{aligned}

\vec{\mu}_{\text{expected}} &= \mathbf{H}_k \color{deeppink}{\mathbf{\hat{x}}_k} \\

\mathbf{\Sigma}_{\text{expected}} &= \mathbf{H}_k \color{deeppink}{\mathbf{P}_k} \mathbf{H}_k^T

\end{aligned}

\end{equation}

$$

One thing that Kalman filters are great for is dealing with *sensor noise*. In other words, our sensors are at least somewhat unreliable, and every state in our original estimate might result in a *range* of sensor readings.

From each reading we observe, we might guess that our system was in a particular state. But because there is uncertainty, **some states are more likely than others** to have have produced the reading we saw:

We’ll call the **covariance** of this uncertainty (i.e. of the sensor noise) \(\color{mediumaquamarine}{\mathbf{R}_k}\). The distribution has a **mean** equal to the reading we observed, which we’ll call \(\color{yellowgreen}{\vec{\mathbf{z}_k}}\).

So now we have two Gaussian blobs: One surrounding the mean of our transformed prediction, and one surrounding the actual sensor reading we got.

We must try to reconcile our guess about the readings we’d see based on the **predicted state** (**pink**) with a *different* guess based on our **sensor readings** (**green**) that we actually observed.

So what’s our new most likely state? For any possible reading \((z_1,z_2)\), we have two associated probabilities: (1) The probability that our sensor reading \(\color{yellowgreen}{\vec{\mathbf{z}_k}}\) is a (mis-)measurement of \((z_1,z_2)\), and (2) the probability that our previous estimate thinks \((z_1,z_2)\) is the reading we should see.

If we have two probabilities and we want to know the chance that *both *are true, we just multiply them together. So, we take the two Gaussian blobs and multiply them:

What we’re left with is the **overlap**, the region where *both* blobs are bright/likely. And it’s a lot more precise than either of our previous estimates. The mean of this distribution is the configuration for which **both estimates are most likely**, and is therefore the **best guess** of the true configuration given all the information we have.

Hmm. This looks like another Gaussian blob.

As it turns out, when you multiply two Gaussian blobs with separate means and covariance matrices, you get a *new* Gaussian blob with its **own** mean and covariance matrix! Maybe you can see where this is going: There’s got to be a formula to get those new parameters from the old ones!

Let’s find that formula. It’s easiest to look at this first in **one dimension**. A 1D Gaussian bell curve with variance \(\sigma^2\) and mean \(\mu\) is defined as: $$

\begin{equation} \label{gaussformula}

\mathcal{N}(x, \mu,\sigma) = \frac{1}{ \sigma \sqrt{ 2\pi } } e^{ -\frac{ (x – \mu)^2 }{ 2\sigma^2 } }

\end{equation}

$$

We want to know what happens when you multiply two Gaussian curves together. The blue curve below represents the (unnormalized) intersection of the two Gaussian populations:

$$\begin{equation} \label{gaussequiv}

\mathcal{N}(x, \color{fuchsia}{\mu_0}, \color{deeppink}{\sigma_0}) \cdot \mathcal{N}(x, \color{yellowgreen}{\mu_1}, \color{mediumaquamarine}{\sigma_1}) \stackrel{?}{=} \mathcal{N}(x, \color{royalblue}{\mu’}, \color{mediumblue}{\sigma’})

\end{equation}$$

You can substitute equation \(\eqref{gaussformula}\) into equation \(\eqref{gaussequiv}\) and do some algebra (being careful to renormalize, so that the total probability is 1) to obtain: $$

\begin{equation} \label{fusionformula}

\begin{aligned}

\color{royalblue}{\mu’} &= \mu_0 + \frac{\sigma_0^2 (\mu_1 – \mu_0)} {\sigma_0^2 + \sigma_1^2}\\

\color{mediumblue}{\sigma’}^2 &= \sigma_0^2 – \frac{\sigma_0^4} {\sigma_0^2 + \sigma_1^2}

\end{aligned}

\end{equation}$$

We can simplify by factoring out a little piece and calling it \(\color{purple}{\mathbf{k}}\): $$

\begin{equation} \label{gainformula}

\color{purple}{\mathbf{k}} = \frac{\sigma_0^2}{\sigma_0^2 + \sigma_1^2}

\end{equation} $$ $$

\begin{equation}

\begin{split}

\color{royalblue}{\mu’} &= \mu_0 + &\color{purple}{\mathbf{k}} (\mu_1 – \mu_0)\\

\color{mediumblue}{\sigma’}^2 &= \sigma_0^2 – &\color{purple}{\mathbf{k}} \sigma_0^2

\end{split} \label{update}

\end{equation} $$

Take note of how you can take your previous estimate and **add something** to make a new estimate. And look at how simple that formula is!

But what about a matrix version? Well, let’s just re-write equations \(\eqref{gainformula}\) and \(\eqref{update}\) in matrix form. If \(\Sigma\) is the covariance matrix of a Gaussian blob, and \(\vec{\mu}\) its mean along each axis, then: $$

\begin{equation} \label{matrixgain}

\color{purple}{\mathbf{K}} = \Sigma_0 (\Sigma_0 + \Sigma_1)^{-1}

\end{equation} $$ $$

\begin{equation}

\begin{split}

\color{royalblue}{\vec{\mu}’} &= \vec{\mu_0} + &\color{purple}{\mathbf{K}} (\vec{\mu_1} – \vec{\mu_0})\\

\color{mediumblue}{\Sigma’} &= \Sigma_0 – &\color{purple}{\mathbf{K}} \Sigma_0

\end{split} \label{matrixupdate}

\end{equation}

$$

\(\color{purple}{\mathbf{K}}\) is a matrix called the **Kalman gain**, and we’ll use it in just a moment.

Easy! We’re almost finished!

We have two distributions: The predicted measurement with \( (\color{fuchsia}{\mu_0}, \color{deeppink}{\Sigma_0}) = (\color{fuchsia}{\mathbf{H}_k \mathbf{\hat{x}}_k}, \color{deeppink}{\mathbf{H}_k \mathbf{P}_k \mathbf{H}_k^T}) \), and the observed measurement with \( (\color{yellowgreen}{\mu_1}, \color{mediumaquamarine}{\Sigma_1}) = (\color{yellowgreen}{\vec{\mathbf{z}_k}}, \color{mediumaquamarine}{\mathbf{R}_k})\). We can just plug these into equation \(\eqref{matrixupdate}\) to find their overlap: $$

\begin{equation}

\begin{aligned}

\mathbf{H}_k \color{royalblue}{\mathbf{\hat{x}}_k’} &= \color{fuchsia}{\mathbf{H}_k \mathbf{\hat{x}}_k} & + & \color{purple}{\mathbf{K}} ( \color{yellowgreen}{\vec{\mathbf{z}_k}} – \color{fuchsia}{\mathbf{H}_k \mathbf{\hat{x}}_k} ) \\

\mathbf{H}_k \color{royalblue}{\mathbf{P}_k’} \mathbf{H}_k^T &= \color{deeppink}{\mathbf{H}_k \mathbf{P}_k \mathbf{H}_k^T} & – & \color{purple}{\mathbf{K}} \color{deeppink}{\mathbf{H}_k \mathbf{P}_k \mathbf{H}_k^T}

\end{aligned} \label {kalunsimplified}

\end{equation}

$$ And from \(\eqref{matrixgain}\), the Kalman gain is: $$

\begin{equation} \label{eq:kalgainunsimplified}

\color{purple}{\mathbf{K}} = \color{deeppink}{\mathbf{H}_k \mathbf{P}_k \mathbf{H}_k^T} ( \color{deeppink}{\mathbf{H}_k \mathbf{P}_k \mathbf{H}_k^T} + \color{mediumaquamarine}{\mathbf{R}_k})^{-1}

\end{equation}

$$ We can knock an \(\mathbf{H}_k\) off the front of every term in \(\eqref{kalunsimplified}\) and \(\eqref{eq:kalgainunsimplified}\) (note that one is hiding inside \(\color{purple}{\mathbf{K}}\) ), and an \(\mathbf{H}_k^T\) off the end of all terms in the equation for \(\color{royalblue}{\mathbf{P}_k’}\). $$

\begin{equation}

\begin{split}

\color{royalblue}{\mathbf{\hat{x}}_k’} &= \color{fuchsia}{\mathbf{\hat{x}}_k} & + & \color{purple}{\mathbf{K}’} ( \color{yellowgreen}{\vec{\mathbf{z}_k}} – \color{fuchsia}{\mathbf{H}_k \mathbf{\hat{x}}_k} ) \\

\color{royalblue}{\mathbf{P}_k’} &= \color{deeppink}{\mathbf{P}_k} & – & \color{purple}{\mathbf{K}’} \color{deeppink}{\mathbf{H}_k \mathbf{P}_k}

\end{split}

\label{kalupdatefull}

\end{equation} $$ $$

\begin{equation}

\color{purple}{\mathbf{K}’} = \color{deeppink}{\mathbf{P}_k \mathbf{H}_k^T} ( \color{deeppink}{\mathbf{H}_k \mathbf{P}_k \mathbf{H}_k^T} + \color{mediumaquamarine}{\mathbf{R}_k})^{-1}

\label{kalgainfull}

\end{equation}

$$ …giving us the complete equations for the **update step.**

And that’s it! \(\color{royalblue}{\mathbf{\hat{x}}_k’}\) is our new best estimate, and we can go on and feed it (along with \( \color{royalblue}{\mathbf{P}_k’} \) ) back into another round of **predict **or **update** as many times as we like.

Of all the math above, all you need to implement are equations \(\eqref{kalpredictfull}, \eqref{kalupdatefull}\), and \(\eqref{kalgainfull}\). (Or if you forget those, you could re-derive everything from equations \(\eqref{covident}\) and \(\eqref{matrixupdate}\).)

This will allow you to model any linear system accurately. For nonlinear systems, we use the **extended Kalman filter**, which works by simply linearizing the predictions and measurements about their mean. (I may do a second write-up on the EKF in the future).

If I’ve done my job well, hopefully someone else out there will realize how cool these things are and come up with an unexpected new place to put them into action.

Some credit and referral should be given to this fine document, which uses a similar approach involving overlapping Gaussians. More in-depth derivations can be found there, for the curious.

]]>

Some kid is pitching his revolutionary startup idea to entrepreneur Elrich Bachman:

Kid: Here it is: Bit… soup. It’s like alphabet soup, BUT… it’s ones and zeros instead of letters.

Bachman: {silence}

Kid: ‘Cause it’s binary? You know, binary’s just ones and zeroes.

Bachman: Yeah, I know what binary is. Jesus Christ, I memorized the hexadecimal times tables when I was fourteen writing machine code. Okay?Ask me what nine times F is. It’s fleventy-five.I don’t need you to tell me what binary is.

We infer that “fleventy-five” is a hexadecimal number, commonly used in coding; presumably it’s 0xF5 (which is *not* 0x9 times 0xF, as it happens). But instead of saying “eff-five” for the byte 0xF5, Bachman has come up with some kind of novel system for the English-ification of hex digits.

He’s on to something. We have ordinary English words for decimal numbers, with names based on the digits and their place-value. “Seventy” is the word for two-digit chunks starting with the digit seven, for example. It might appear in the number “seventy-three”, or “five hundred seventy-one thousand”; both numbers with a 7 digit in an appropriate place. “Fleventy”, then, would be the number for two-digit chunks starting with F.

Hex only adds more kinds of digits (the symbols A through F). Could we follow Bachman’s lead and add more number-names for the extra digit symbols, and pronounce hex just like a decimal number? Could we have a system that attains the unwieldiness and syllable count of spoken English numbers, with all the respectable seriousness of saying the word “fleventy”?

I’m glad you asked. This has never been done before^{(1)}probably, but fear not; here are the official new number-words for hexadecimal. You may start using them immediately:

Hex Place value | Word |
---|---|

0xA0 | “Atta” |

0xB0 | “Bibbity” |

0xC0 | “City” |

0xD0 | “Dickety” |

0xE0 | “Ebbity” |

0xF0 | “Fleventy” |

I think it would help to solidify this with some examples:

**0xB3** *“bibbity-three”
*

But really, we must go further. What about numbers larger than a byte? We have the words “hundred” and “thousand” for decimal place values higher than ten, so why not something for hex place values higher than 0x10? Say, for multiples of 0x100?

For this, I propose “bitey”.

Resulting in:

**0xDAF1** *“dickety-A bitey fleventy-one”*

**0xE137** *“ebbity-one bitey thirty-seven”*

**0xA0C9** *“atta-bitey city-nine”
*

Naturally, we could make yet larger numbers by devising some names for larger place values, and combine them with intermediate values, in the same way that we compose decimal numbers like “thirty thousand” or “six hundred fifty one million”. As in English, place value names could be dropped if you’re feeling brief. We’ll also need hex-digit words for the “teens”.

I’ll leave you to explore the new naming system with this toy:

How we’ve conversed about hex without a system like this is beyond me. *You’re welcome.*

Footnotes

1. | ↑ | probably |

This was last week’s project: Building a Kalman filter-based IMU.

IMUs (inertial measurement units) are clever little devices which try to estimate an object’s absolute orientation (and sometimes its position) by examining the forces on the object.

Hobby drone and computer input IMUs generally look at acceleration data (which informs where “down” is), compass data (which points toward north in 3D space), and rate gyro data (which tells the axis and speed of spin). “Down” and “north” in combination can give a pretty accurate constraint on orientation, but unfortunately if there are any lateral forces (wind; turning), they will get mixed in with “down” and distort the estimate. Kalman filters use matrix math to make good use of the gyro data to correct for this. However, a constantly-accelerating drone could still be fooled about where down is.

I’ve tried here to find out whether we can try to model the drone’s translation and take this into account when estimating the orientation. It turns out that even relatively poor and infrequent data about velocity can constrain acceleration— and thus “down”— quite well. The difference in the quality of the estimate is plainly visible.

This is all done by mathematically simulating a 3D moving object using ordinary dynamics and battering it with Gaussian random forces, and then predicting what data a noisy sensor might return. A predictor algorithm using a Kalman filter (which has no knowledge about the original state) attempts to recover the true state to the best of its ability. The truth is rendered white here, and the estimate in red.

At the end you can see the same algorithm running on actual sensors. The real thing doesn’t use GPS yet, but the prediction is still pretty decent! (There is not that much sustained acceleration to throw it off in this video).

I’ve done some other cool things with the code which perhaps I’ll write up in the future: Among them are a process noise model based on Gaussian random walks, and a nice extension of it to quaternions (which has dramatic impact on the quality of the estimate!) I also make use of automatic differentiation, which makes a linearized extended Kalman filter (EKF) particularly easy and robust to implement.

]]>