Archive for March, 2017|Monthly archive page

ASAP Smoothing

Last week, Peter Bailis announced a new tool for smoothing timeseries data for plotting, called ASAP:

Since I just happened to have some fresh data handy, I decided to try it out. You may recall this graph of the difference in pressure measured between a sensor submerged in fermenting beer, and a sensor in open air:


Helium-smoothed pressure data (190 points)

That graph was based on data that was pre-smoothed using a windowed average provided by the Helium API. The window is one hour, which produced 190 points. Zooming in just a little bit takes us to a 30 minute window, at 303 points:

Screen Shot 2017-03-11 at 12.20.49 PM

Window-averaged pressure data (303 points)

Unlike the other graphs I plotted in that series, I didn’t plot the maximum and minimum on this one. Here is what the raw data looks like:

Screen Shot 2017-03-11 at 4.49.51 PM

Raw pressure data (11282 points)

That is 11282 points. There are spikes several times taller than what looks like the “typical” variation. The question, then, is did the windowed average portray this data accurately? Here are 303 points overlayed on the 11282 (I cut off the peaks to give us a little more detail):

Screen Shot 2017-03-11 at 12.31.02 PM

Raw pressure data (grey) with Window-averaged data (blue)

I think it seems reasonable. A little noisy, but visually following the mid-point of the band. Can ASAP do better? Here are the 304 points it gives when asked for 303 from this dataset:

Screen Shot 2017-03-11 at 12.37.14 PM

Raw data (grey), window-averaged (blue), ASAP (red)

If you look closely, you can see a few blue edges from the windowed average peaking out from under the ASAP plot, but they’re largely the same. ASAP hasn’t surfaced any additional features in this data that the plain windowed average hid. I think that’s not surprising. The process that was being measured was a slow, continuous change, and not something where there should have been sudden changes in behavior.

So instead, let’s look at some data with an anomaly, like the absolute-force graph from the tilt sensor:


Helium-smoothed force data (dark blue) with min-max area (light blue)

That was using window-averaged data as well. Let’s plot it against raw data and ASAP like before:

Screen Shot 2017-03-11 at 4.28.48 PM

Raw force data (grey), window-averaged (blue), ASAP (red)

That’s strange. The blue window-averaged line follows the raw data pretty well, at the 303 points I asked for. The ASAP line looks weirdly off, though. The smooth function only returned 279 points, and it’s caused by a gap in the middle. That straight line around the anomaly contains 30 points. The fact that the curve to the left of that line looks like it’s shifted in time makes me suspicious, but there seem to be no errors generated. Even if I bump up the resolution to the full 890 pixels of this SVG, the ASAP curve looks like this, and produces 31 fewer points than the windowed-average.

The data and code I’m using to plot it are available in this gist:

Off to ping Peter…

Beer IoT (Part 8)

Strike up the band, it’s time for the eighth, and final, installment of this fermentation instrumentation series. In part four, I placed several different sensors in several different carboys of beer beginning fermentation. In parts six and seven, I analyzed a week of data from two of the sensors. This post will cover the third sensor, a floating accelerometer.


The ADXL345 provides three readings for each sample: one for each axis in 3D space. I’m using the chip in “2g 10-bit” mode, which means each axis will report a number from -512 (2g negative acceleration) to +512 (2g positive acceleration). In this case, the only acceleration I want to measure is gravity, so I should see only values between -256 (1g negative acceleration; “this axis is pointing straight down”) and 256 (1g positive acceleration; “this axis is pointing straight up”). Using a bit of trigonometry, I should be able to figure out the angle at which the sensor is tilted.

My float is sort of a rounded rectangular prism. I’ve oriented the sensor such that the y-axis is in line with the long axis of the prism, with the positive end pointing toward the end I expect to float. The x-axis is horizontal across the short axis of the prism, and the z-axis is pointed “up”. The expectation is: y will start about zero, or slightly positive, as high buoyancy keeps the float “flat”; x will start about zero as well, because any dip should be along y; and z will start near max, almost straight up. As the beer ferments, reduced buoyancy should cause one end to dip, causing y to increase (because it will point upward more steeply), and z to decrease (because it will move off of straight upward), with x staying the same (because the rotation should be around that axis). So what actually happened?


Pictures may be worth a thousand words, but I’m pretty sure this one just says, “Not that.” We have both x and z increasing, and y is doing … I’m not even sure. Let’s see if there is anything to salvage.

Let’s check an assumption first. I’m expecting to only see acceleration from gravity here, so the total acceleration should always be 1g (plus or minus some measurement noise). We can check that with a bit of Pythagorus: the square root of the sum of the squares of the readings should be a constant 256.


Except for the sudden change in the middle, it’s a variance of about 1, which is 0.0039g for this chip. It’s interesting that it’s only 252 max, and I have no idea what that sudden shift is (it seems correlated with a sudden shift on the z axis, but nothing on the other axes), but it does look like we’re measuring approximately a constant 0.97-0.98g force.

The increasing x may a bit of a red-herring. It just means that the tube is “rolling” (turning around its long axis). This is why z is increasing as well: x returning to horizontal around the unchanging y axis means that z is returning to vertical. There is a chance that the float is rolling instead of tipping as buoyancy changes. This might be worth returning to later, but let’s see if we can save y first.

Despite the fact that our sanity check showed that we’re reading constant gravity as we expect, and therefor all axes agree, we could use Pythagorus again to compute what the value of the y reading should have been, given x, z, and our expected force:


The synthesized y reading is in blue, while the actual y reading is in red. This graph used 256 for the expected gravity. Let’s instead use the 253/250 mix we saw before, which will also account for that unexplained shift in z:


Many features are similar between these plots, but we appear to have exaggerated a somewhat steady descent in y during the period that x and z where steadily climbing (Feb 19 through 21). I expected y to start around zero and become more negative over time. Starting above zero, and decreasing anyway just means that the sensor was tilted away from the expected sinking angle to start. Interestingly, y moving from slightly up to closer to horizontal will also have the effect of bringing z up closer to vertical, just like x moving from negative toward zero did.

If the rolling is not the result of buoyancy change, then this change in y alone leaves us with a change from early Feb 19 mid afternoon Feb 21 of either 33-22 (computed, blue line) or 10-5 (observed, red line). asin(33/256) = 7.41º, asin(22/256) = 4.93º; asin(10/256) = 2.24º, asign(5/256) = 1.12º. Using 252 instead of 256 only alters the result by 0.1º. So, a change of at most 2.5º, and at least 1º. A bit of a narrow bad, if you ask me.

If the sensor shifted during placement, the x axis might be measuring pitch instead of roll. But if even if not, what if the fermentation primarily produced rolling instead if pitching? The x reading swings from -115 to -100. That’s 26.7º to 23º, meaning a change of 4.3º. That’s more, is about all that can be said about that.

If we take both roll and pitch together, we can just consider the change in z, but we also have to ignore the sudden shift near the end of the time range we were looking at. That gives 223 to 231, or 60.59º to 64.46º. Still just 4º change.


If I return to the design of the float, its weight of the float is 1.8oz. So, to float in fresh water, it will have to displace 1.8oz, or 3.24 cubic inches. The float is 4 inches long, by 1 3/16 inches wide, by 7/8 inches tall. A rough estimate places that at 4.15625 cubic inches. The rounded edges are tricky, though. Measuring via displacement shows it’s actually about 3.5 cubic inches. So, what I have is a float that is only just barely floating in water. That was the aim, and what was observed, but good to see the math line up.

If the float has to displace 3.24 of water at specific gravity 1.000, then at our starting gravity of 1.040 it only has to displace 3.12 of unfermented beer, and 3.22 of beer at the finishing gravity of 1.0075. So we’re looking at a change of 0.1 cubic inches of displacement.

I found the center of mass to be about 3/8 inch closer to the end that is expected to sink. That’s not a huge margin of influence, but since the float will be almost entirely submerged anyway, it’s probably enough. The heavy end also happens to have less volume, due to the curvature, so it should have to sink more to displace the same amount.

Calculus is probably the correct way to solve this problem. 18.01 was a long time ago, though, so I’m hoping I can fudge it. Instead of trying to figure out how far this float should have tipped, let’s figure out if a 4º pitch could have changed the displacement 0.1

If we’re already mostly-submerged, we’re looking near an edge that is not 1 3/16 inches wide, but instead closer to 0.75 in (due to curvature). If the float were flat (which the y and z axis readings mostly suggest), 0.75 * 3.75 in would be above water 0.036 in. If we pitched that 4º, we would lose 0.12 cubic inches into the water:

Height lost at 4º over 3.75″: (sin(4/180)*3.75) = 0.08332647479 inches

Volume of 0.083 x 3.75 x 0.75 ” triangular prism: 0.75 * (0.083 * 3.75)/2 = 0.117 cubic inches

So 4º could actually the correct change for these parameters! This does require that the x and z axes were reading pitch, and not roll, though. A 4º roll with these parameters is only a change of about 0.02 cubic inches.

A final check: how well does the shape of this data match the shape of the BeerBug’s?


Comparing the Z axis, it looks like the story is similar to the pressure sensor: the change plateaus at about the same point as the BeerBug, signaling the end of primary fermentation. If the 4º change was measuring the correct thing, then math would have told me the correct final gravity, but it would have been much easier to have developed a calibration table with known angles of specific gravities beforehand.

That wraps up this experiment. I’ve added this data to the gist containing the other sensor data. What’s next for this beer sensing story … ?

For the BeerBug, it may be worth continuing to use their service. The device works when the service works, as shown in this data. If anything, I think I’d work on snooping its communication, so I could tee it off to my own storage, in case their service goes down again.

For the pressure sensor, it’s mostly about a new housing, and then calibration to that housing. It needs something that is both heavy enough to sink, and also flexible enough to compress. If both of those are taken care of, it seems like calibrating to known specific gravities may actually provide decent data.

For the tilt sensor, it’s also about a new housing. The weight distribution needs to be far more unbalanced, to ensure a larger change in angle. Something narrower, so that more sinking is required to balance displacement, would work to. If those can be taken care of, then calibration may make this as good as other options.

Both the pressure sensor and the tilt sensor would also benefit from getting the Helium Atom and battery onboard. Current results are probably affected by the cable running out of the carboy. For now, this would require fermenting in something with a wider neck, since the development board is too wide to fit in the carboy. That’s easy to do, and would avoid me having to design my own printed circuitry.

What was really amazing to me is how easy this sort of thing has become. A week after I got hardware, I put it into service. I2C is a nice standard communication protocol. Lua is a quick language to pick up. The Helium chip, library, and service work very smoothly. Between the dev kit and the sensors, I’m over $100, but less than $200 into this exploration. I can see why people are excited about IoT these days – it’s easy to get started, and fun to participate.

But for now, there are two cases of beer to sample in a couple of weeks, and they’re stacked under earlier brews, so I won’t have any more fermentation to measure for a while. I’m setting up one of my Atoms to monitor the temperature in the conditioning closet. I wonder what I should start measuring with the other.

Beer IoT (Part 7)

Keeping on the hop, it’s time for part seven of this fermentation instrumentation series. In part four, I placed a few different sensors in some actively fermenting beer to gather data. In the previous post, I looked at data from a commercial sensor. Now it’s time to examine the data from my experimental pressure sensor.


I have two atmospheric pressure sensors collecting data while this beer ferments. One is outside the carboy, while the other is in a non-rigid (i.e. squeezable) container near the bottom of the inside of the carboy. The idea is that as the beer ferments, it will become less dense (because alcohol is less dense than sugar), and thus the same volume of liquid will put less pressure on the sensor.

Let’s start with predictions. I took the long way around and made a table that says that if my sensor is four inches below the surface of the water (it is), it should see about nine millibars of pressure more than just sitting in the air, regardless of specific gravity. This was the long way around, because it turns out “water-inch” is a known pressure unit (equal to 2.49mbar).

Screen Shot 2017-02-27 at 9.17.30 PM.png

Here is what my sensors measured:


Blue: External Pressure, Red: Internal Pressure

Unfortunately, there are two problems, relative to my predictions. The first is that the curves are not 9mbar apart. The second is that the red one is the internal sensor, consistently reading lower than the external sensor. Before I put the sensor in the carboy, I saw about the same difference. It’s possible that the missing 9 mbar is due to the fact that the sensor housing is not laying on the bottom of the carboy, as in the picture at the top of this post, but is instead resting with one end higher than the other. That means the pressure on it is not uniform, and I could be losing all of the additional pressure to the top end (which also happens to be the most flexible end). This might be enough to declare the experiment invalid, but let’s continue looking at what I have anyway.

What is more interesting from the earlier table is the difference we’re supposed to see as the beer ferments. I measured an original gravity (OG) of 1.040 when I pitched the yeast, and a final gravity (FG) of 1.00075 when I bottled (there are some sugars the yeast won’t eat, so we don’t reach 1.000). The predicted difference in pressure is just over 0.3 mbar. The pressure varies by over 15 mbar just due to the weather, though, so how can we tell? By subtracting the external, weather-only pressure from the internal, weather+beer pressure:


Hooray! We do see relative pressure change in the carboy. It’s noisy, but I think we have to compare the top-ish of the hump with the resting level of the plateau on the right. Why not compare the start point at the left with the resting point at the right? The climb on the left is likely one of two things: something similar to what the BeerBug sees, as discussed in part six (i.e. initial oxygen consumption, carbon dioxide production, or yeast proliferation), or the sensor moving. In either case, it does take the yeast 12-24 hours to really get working, and that’s about where the climb levels off, so that’s where the conversion of the sugar really starts.

Drawing some lines across the difference graph, I find the “max” pressure to be about -1.65, and the “end” pressure about -2.05, a difference of 0.4 mbar. That’s 30% off of the hypothesis. This doesn’t seem like a bad error (for a first attempt), but I’m skeptical that we saw this much pressure change without seeing the entire pressure difference (the missing 9 mbar).

So, let’s see if we can answer some unknowns. Before removing the sensor from the carboy, I attempted to figure out if the pressure leveled off higher due to pressure from the airlock. There is about a half inch of water that has to be moved out of the way, which would be 1.2 mbar. That’s nearly double the difference between the start pressure and the resting pressure, but to check, I let the gas out a couple of times between 5pm and 7pm in this graph:

Screen Shot 2017-02-27 at 8.48.28 PM.png

There is no dip in pressure, just added noise from me jostling the cable. The resting pressure change is not from pressurizing the airlock. Follow-up experiments will be necessary to determine if it has anything to do with the specific mixture of absorbed gases, or the presence of yeast cells, I think for now the most likely answer is that the sensor moved.

I also tried to find the missing 9 mbar. After removing the sensor from the carboy, I put it in another container under about 4 inches of water, fully horizontal this time.


That graph starts with the sensor in the open air. It looks like I found about 6 mbar once I got the sensor truly in the bottom of the container. I think the last 3 mbar can probably be attributed to the rigidity of the container – it probably couldn’t deform further.

Perhaps most importantly, how does this compare to the BeerBug’s specific gravity curve? If I do just a little scaling and shifting, I can lay the curves on top of each other:


Blue: Differential Pressure, scaled and shifted; Red: Specific Gravity as measured by BeerBug

The two carboys do contain different strains of yeast (the original reason for using three separate carboys), and the BeerBug’s carboy started noticeably faster. So, the different in the start of the curves is to be expected. The head in both, and the bubbling out of the airlocks of both did seem to reduce at about the same time, so the simultaneous arrival at finishing plateau is expected as well.

Overall results are, unfortunately, inconclusive. It looks like the end of fermentation was signaled correctly. I would not have been able to predict the finishing gravity, though. There is enough here to warrant future experiments, I think. This was something of an opportunistic test. I was brewing these three batches anyway, so why not try the sensors? Something with more control (i.e. taking fermentation out of the equation) should be illuminating.

If you want to explore this data yourself, I’ve posted the data in CSV format in a gist.

Stay tuned for the final episode analyzing the accelerometer data soon!

Update: accelerometer data is live in part eight.

Beer IoT (Part 6)

Welcome back for part six of the fermentation instrumentation series. In part four, I placed a few different sensors in some actively fermenting beer to gather data. A week has now passed, and I’ve bottled the beer. Time to look at the data. Let’s start with the device we know – the BeerBug.


We’re lucky this time. New owners have just taken over BeerBug operations, and they’re relaunching the product. Unfortunately, that means they’re going through a bumpy transition period. While I was brewing, I could see the latest reading from my beer, but none of the history. But, after a lengthy email exchange, they have pulled through, and I have the data for this batch.

As before, I’ve uploaded the data to Helium’s servers. This is mostly so I can use the same tools for processing the data for all three of the batches in this experiment. So, with out further ado, this is how the BeerBug thought the specific gravity of my English Mild changed over the week:


This is pretty typical. All the way at the left, we have the gravity that I specified as my starting point, what I read from my glass hydrometer: 1.039. The phenomenon that has been observed for every beer, but is as yet unexplained, comes next: the climb to a higher gravity. This probably has something to do with the initial yeast activity, as they rapidly reproduce throughout the beer, consuming the dissolved oxygen, and beginning to produce carbon dioxide. The gas exchange or cell proliferation may change the buoyancy observed by the BeerBug’s float.

After the initial climb late Saturday, we dive right into the expected steady decline in gravity over the next few days. By night time on Tuesday, the gravity has nearly leveled off. A much slower decline continues as the few yeast cells that haven’t starved continue to find some sugar to eat. By the time I bottled on Sunday, the BeerBug read 1.006. My regular glass hydrometer agreed ±0.001. That’s pretty impressive.

The other thing that seems impressive is that there is far less noise in this data than there was in the BeerBug data from part three of this series. I think the explanation for this begins with the fact that there are fewer points in this dataset. In part three, there was a reading every minute. In this dataset, there is sometimes a reading every minute, but sometimes a reading only every 3, 5, or 10 minutes. This might represent a new strategy in the BeerBug firmware – if the measurement variation was white noise, averaging over longer periods should reduce it. Or, it could be just missing data, which would make the error band (the light blue) close in on the average (the dark blue), because the average *is* the data if you remove enough.

The BeerBug also has a temperature sensor in the housing that sits above (outside) of the carboy. Here is its data, in blue, with the temperature data we looked at from one of the Helium boards in part five of this series, in red:



The readings begin only a degree and a half or so off, but the drop into Sunday morning is deeper for the BeerBug. Its readings also stay consistently nearly 3ºC cooler. This was unexpected, given the placements of these sensors. The Helium sensor was closer to an external door, and the BeerBug was just a few inches above active yeast. I’ll chalk it up to simple differences in the characteristics of the sensors, for now.

I’ve uploaded this data to a gist in CSV format, if you would like to examine it yourself. In the next post, we’ll look at the data from the pressure sensor, and see if we can find a shape similar to the BeerBug’s.

Update: part seven is live with pressure data.