## Applied Tea Science

16.08.2015 21:14

What happens when you pour boiling water into a tea cup? It steams a little. There is a possibility of thoughts on the meaning of life, universe and the ungodly hour of the morning. Some unfocused staring out the window might be involved. Eventually, the tea cools and you are free to enjoy a sip of the lukewarm beverage.

But what really happens? How does the tea in your cup cool down? We could start with convection, conduction and radiation. On the other hand, we are living in the year of the Internet enabled coaster and sensors on every step. It's not unusual to hear the sentiment today that scientific theories and good old-fashioned reasoning have nothing on big data and machine learning. So let's go with that for a moment and try to answer this question.

Enter my hastily thrown-together smart tea cup. No, it doesn't take selfies. It consists of a thermocouple sensor positioned to measure the temperature of the liquid approximately at the center of the volume. It is held in place by a RFC 2322-compliant wooden peg. A Python script takes periodic temperature read-outs using a computer-connected multimeter.

The cup, which I suspect was originally meant for Irish coffee, rests on a lid from a Nutella jar. Inside the lid is a Texas Instruments SensorTag. It measures the temperature of the bottom of the cup through an infra-red thermopile sensor and also takes readings of the temperature of its PCB. Data from the SensorTag is sent over Bluetooth to an Android phone, which forwards it over the wireless LAN to a MQTT broker. From there, a second Python script records the two temperature values to a file.

The Nutella lid rests on a kitchen scale, which will be relevant a bit later. For the sake of the argument, imagine a lab assistant taking regular notes of the weight read-outs.

I left the whole setup for an hour to settle. After the readings on all sensors stopped changing, I brought some water to a boil and poured it into the cup (no actual tea was involved). A couple of hours later, I got the following result:

This is after some light-weight preprocessing of raw data: I compensated for the offset of sensors, assuming that they were all at the same room temperature before the start of the experiment. A gap in the data nicely demonstrates the current state of the Internet of things - the SensorTag application stopped responding at some point and needed a restart.

At the first glance, this is a pretty typical progress of a relaxation process. Each sensor shows a sum of exponential decays. Three characteristic time constants are visible: the shortest one is defined by the heat transfer between the water and the cold cup, τwat-cup. The second one is of the heat transfer between the cup and SensorTag's PCB, τcup-sur. The longest one is of the heat transfer between the whole thing and the ambient environment, τamb. From the graph it's possible to roughly estimate these:

\begin{array}{rcrl} \tau_{wat-cup} &\approx& 10 &\mathrm{s}\\ \tau_{cup-sur} &\approx& 200 &\mathrm{s}\\ \tau_{amb} &\approx& 3000 &\mathrm{s}\\ \end{array}

This makes sense: water and cup are in very good thermal contact and water can quickly heat up the cup. On the other hand, air surrounding the cup is a relatively good insulator and it takes a long time for the water to cool back down to the room temperature. The simplest thermal circuit model that could fit this behavior is the following:

This model allows us to express the time constants with parameters of the model, the thermal resistances and capacitances. Since the time constants differ in orders of magnitudes, the first approximation is quite simple:

\begin{array}{rcl} \tau_{wat-cup} &\approx& R_{wat-cup} \cdot (C_{wat} \parallel C_{cup}) \\ \tau_{cup-sur} &\approx& R_{cup-sur} \cdot C_{sur} \\ \tau_{amb} &\approx& (R_{wat} \parallel R_{cup} \parallel R_{sur}) \cdot (C_{wat} + C_{cup}+C_{sur}) \\ \end{array}

While estimating the model parameters from these equations would make for a satisfying mental exercise, let's instead make use of the fact that computers are ridiculously fast these days. Numpy comes with a slew of non-linear multi-variate optimization algorithms. I chose the Powell's method to minimize the integral square error between a simulation of the model and measurements for the three time series. I won't go further into this process since this post is already getting long. Drop me an email and I can share the details.

However, before blindly running the optimization, it's worth noting that we can easily determine one of the parameters, hence eliminating one of the unknown variables and making the computer's job a bit easier. If we knew the amount of water in the cup, Cwat can be calculated from water's specific heat capacity. I told you the kitchen scale would come handy.

C_{wat} = m_{wat} \cdot c_{wat} = 370 \mathrm{g} \cdot 4.2 \frac{\mathrm{Ws}}{\mathrm{gK}} = 1550 \frac{\mathrm{Ws}}{\mathrm{K}}

Given this input and a few minutes of increased fan noise, the computer arrived at the rest of the model parameters:

\begin{array}{rcr} C_{cup} &=& 168 \frac{\mathrm{Ws}}{\mathrm{K}} \\ C_{sur} &=& 923 \frac{\mathrm{Ws}}{\mathrm{K}} \\ &&\\ R_{wat} &=& 1.57\cdot 10^{10} \frac{\mathrm{K}}{\mathrm{W}} \\ R_{cup} &=& 7.12 \frac{\mathrm{K}}{\mathrm{W}} \\ R_{cup} &=& 0.990 \frac{\mathrm{K}}{\mathrm{W}} \\ &&\\ R_{wat-cup} &=& 0.0771 \frac{\mathrm{K}}{\mathrm{W}} \\ R_{cup-sur} &=& 0.723 \frac{\mathrm{K}}{\mathrm{W}} \\ \end{array}

And here are the results of the simulation, super-imposed over the measurements from the previous graph:

The simulation matches the reality quite well. One interesting deviation is the flatness of the cup temperature curve in the first few minutes of the experiment. It is obvious that the sum-of-exponential-decays that is inherent in the model can't reproduce that. What is the physical origin of that is a bit puzzling. It is probably due to the fact that neither water nor the cup is a lumped element. Convection of water is an especially inviting excuse.

How realistic are parameter values? Knowing the mass of a dry cup (395 g), we can calculate the specific heat of the cup's material from Ccup. This gives 425 J/kgK which I would say is a bit on the low side for ceramics.

The value that sticks out most is, of course, the Rwat. It appears that the model optimization arrived at the fact that water cooled exclusively through the cup and basically no heat escaped into the ambient from the water itself. This is an interesting conclusion, but one that is also most definitely wrong.

While the surface of the cup is indeed larger than the surface of water exposed to the air, a hot body of water will cool itself through evaporation. This is an incredibly efficient process. Comparing the mass of water in the cup before and after the experiment showed that 23 g of water went missing. From water's heat of vaporization we can calculate how much heat got carried away by water vapor:

\Delta Q = \Delta m_{wat} \cdot q_t = 23 \mathrm{g} \cdot 2200 \frac{\mathrm{J}}{\mathrm{g}} = 51 \mathrm{kJ}

This is in fact around 45% of the total heat exchanged during the experiment. Since evaporation rate depends on the temperature and our model is time-invariant, this likely affected the other calculated parameters as well.

One final interesting exercise that this model allows is to calculate the magnitude of heat fluxes in the system. Particularly between water and cup and towards the ambient environment:

Compared to, say, your ordinary iPhone USB charger that maxes out at around 10 watts, these values may look large. During the experiment the cup exchanged enough heat for around 5 typical smart phone battery charges. However, the laws of thermodynamics are a harsh mistress. Due to low temperature differences it would be impossible to convert this heat into electrical work with any kind of practical efficiency.

What advances has this exercise brought to the existing body of knowledge about tea cups? One interesting discovery is that pouring hot water into a cold cup contributes to an immediate temperature drop of around 10 K, which makes it necessary to adjust the volumetric mixture ratio for green tea. This phenomenon was overlooked by the little known Indonesian tea research unit, which just highlights the need for independent verification of experimental results. Another result is the aforementioned fact that the temperature of a cup's bottom is not well correlated with the temperature of water during the first few minutes. This has practical implications, since it makes it hard to accurately reason about temperature of the cup's contents solely from a sensor in the (Internet enabled or otherwise) coaster.

Posted by | Categories: Ideas | Comments »

## Using Metex M-3860D from Python

08.08.2015 15:56

Metex M-3860D is a fairly old multimeter with a computer interface. It uses a RS-232 serial line, but requires a somewhat unusual setup. It does work with modern USB-to-serial converters, however a serial terminal application like cutecom won't work.

Here is a Python recipe using pyserial (replace /dev/ttyUSB0 with the path to your serial device):

import serial

# 1200 baud, 7 data bits, 2 stop bits, no parity, no flow control.
comm = serial.Serial("/dev/ttyUSB0", 1200, 7, "N", 2, timeout=1.)

# DTR line must be set to high, RTS line must be set to low.
comm.setDTR(1)
comm.setRTS(0)

# The instrument sends back currently displayed measurement each time
# you send 'D' over the line.
comm.write('D')

# This returns 14 characters that show type of measurement, value and
# unit - for example "DC  0.000   V\n".


The correct setting of the DTR and RTS modem lines is important. If you don't set them as shown here, you won't get any reply from the instrument. This is not explicitly mentioned in the manual. It's likely that the computer interface in the multimeter is in fact powered from these status lines.

Posted by | Categories: Code | Comments »

## Improving privacy with Iceweasel

06.08.2015 19:35

For several years now Debian has been shipping with a rebranded Firefox browser called Iceweasel. As far as I understand the matter, the reason is Mozilla's trademark policy which says that anything bearing the Firefox brand must be approved by them. Instead of dealing with the review process for each Debian-specific patch, Debian maintainers chose to strip the branding from the browser. This is something Mozilla's code actually makes provisions for.

The Iceweasel releases from the Debian Mozilla Team closely track the upstream. In contrast to other Firefox forks, changes to Iceweasel generally only improve integration with the Debian system. Packages released with the stable releases might also contain backported security fixes (although this might change soon).

A problem with Iceweasel is that it also identifies as such to all websites it loads through its User-Agent header. Iceweasel is quite a rarity among browsers, which makes its users easy to track across web pages. Currently EFF's Panopticlick shows that Iceweasel 39's User-Agent provides around 16 bits of identifying information. In contrast, a vanilla Firefox on Linux gives trackers around 11 bits. EFF's numbers change quite a lot over time though - I've seen 22 bits reported for Iceweasel a few weeks ago. In any case, if you have friends that like to watch Apache logs for fun, it's quite obvious when you're hitting their blogs if you are using Iceweasel.

In order to improve this situation I've created a very simple add-on for Iceweasel that removes the reference to Iceweasel from the User-Agent header. It consists only of a few lines of Javascript that run a regexp replace on the built-in User-Agent string and set the general.useragent.override preference. The User-Agent set this way should be identical to the vanilla Firefox of the same version running on Debian.

The extension is not on addons.mozilla.org, so you will have to fetch it from GitHub and build it yourself (git clone followed by make should do the trick).

How well does it work? Panopticlick shows the expected reduction of around 5 to 6 bits of identifying information. Which might not matter if the site is actively trying to fingerprint you and can run Javascript - system fonts and browser plugins are still very unique for a typical Debian desktop. But at least you don't stick out from access.log as a sore thumb.

You might ask why not just use one of the myriad existing User-Agent overrider add-ons. The trick is that I have not found any that would allow you to apply a search-and-replace regexp on the built-in User-Agent string. Without that, you either have to manually keep it up-to-date with the actual browser version, or risk sporting a unique, out-dated User-Agent string once everyone else's browser has auto-updated. I don't want my computer to have another itch that needs regular scratching.

A related argument against this add-on would be that providing an accurate User-Agent string is good etiquette on the web. It helps administrators with browser usage statistics and debugging any browser-specific problems with their web-sites. Considering that the idea of Iceweasel is to have minimal changes against the upstream Firefox, I think it is still within the boundaries of good behavior to present itself as Firefox. Whether this argument is valid or not is up to debate though. At the time of writing, Iceweasel 39.0-1~bpo70+1 has 36 patches applied against the upstream Firefox source, touching around 1800 lines of code.

Finally, of course, you can just install Mozilla's Linux build of Firefox on Debian. I'm sticking with Iceweasel because I prefer software managed through the package manager instead of dumping tarballs into /usr/local. Adding another distribution's repositories into Debian's /etc/apt/sources.list is just wrong though.

Posted by | Categories: Code | Comments »