Sous-vide cooking with the Wolfram Language

Here’s another guest post from Allison Taylor at Wolfram Research. We’ve seen sous vide applications before – but we’ve never seen one that uses the Wolfram Language and Mathematica to describe elegant curves while it prepares your dinner. Thanks Allison, and thanks to Diego Zviovich, who came up with this project.

Diego Zviovich, another one of our ambitious power-users of Mathematica and the Wolfram Language on the Raspberry Pi, has managed to (affordably) master the science of sous-vide cooking!

For those who aren’t familiar, sous vide is a modern cooking practice where the food is first put into airtight bags and then cooked in a water bath at a very precise temperature. The result is perfect, evenly cooked meat or fish, with much greater penetration of flavours from any marinade you might be using. Actual sous-vide cookers cost hundreds (or thousands) of dollars to buy, but with a few sensors, a crock pot, and your Raspberry Pi with Mathematica installed, you can create your very own sous vide at a fraction of the price!

What you’ll need (along with your Raspberry Pi + Wolfram):

The 5V 2-relay control module will be used to control the power to the crock pot. We’ll be automating this switch to turn on and off depending on our thermocouple readings, maintaining the appropriate constant temperature that we want. A walk-through for setting up a circuit and connecting the relay from your crock pot to your RPiPi can be found in this handy YouTube tutorial.

Once set up, turning the crock pot on and off with the Wolfram Language is very straightforward. To turn it on:


And to turn it off:


In order to get the temperature readings using thermocouples, we’ll need to set up an analog-to-digital converter—since the GPIO on the RPi does not have analog pins. A wiring diagram for the MCP3008 can be found here.

We’ll only be using two of the eight analog sensors for our two thermocouples (one for the water bath and one for the food probe). They must be connected to the CH0 and CH1 inputs of the MCP3008 in the following way:


Once you’ve decided at what temperature you want to cook your food, you can conduct a simple experiment to determine the ideal fixed resistance value that you will need to effectively maintain it. Using your thermocouples, a regular thermometer, a voltmeter, and three glasses of water—one iced, one warm, and one hot—take three temperature measurements and three resistance measurements (one from each glass of water) and fit the data to a curve using Mathematica.

Using Diego’s data as an example:

temp = {20.6, 42, 83.3} + 273.15
resistance = {220650., 95800., 26340.}
data = Transpose[{Log@resistance, Log@temp}]
lm = LinearModelFit[data, x, x]

The model above fits very well (R^2=.998), so we can use the curve to find the expected resistance at our desired temperature. For this example, let’s say 60 degrees Celsius.

invdata = Transpose[{Log@temp, Log@resistance}]
Fit[invdata, {1, x}, x]
(*74.3895 - 10.9297 x*)
f[x_] := 74.38949510675315` - 10.929736543045369` x
Exp[f[Log[60 + 273.15]]]

From these results, using a 56K resistor for the thermocouples will provide the appropriate temperature range we need.

To read the temperature values from the thermocouples, we will need to probe the analog inputs from the MCP3008 through the GPIO. We will develop a function to do this, using two libraries — gpio.h and mcp3008.h — that can be downloaded here, along with the script to export the GPIO pins to sys/class/gpio. Put the library files into the directory /usr/include. Make sure to run:

update-rc.d -f gpio defaults

after the installation. With these libraries installed, we can now build a function to get the temperature values using MathLink. The two files will be as follows:

:Begin: adc
:Pattern: adc[adc_Integer, clock_Integer, in_Integer, out_Integer, cs_Integer]
:Arguments: {adc, clock, in, out, cs}
:ArgumentTypes: {Integer, Integer, Integer, Integer, Integer}
:ReturnType: Integer



int adc(int adc, int clock, int in, int out, int cs) {
 return mcp3008_value(adc, clock, in, out, cs);
int main(int argc, char *argv[]) {
 return MLMain(argc, argv);

Compile the files by running

mcc adc.c –o adc

And now we can open up the Wolfram Engine or Mathematica and build the sous-vide program!

(*We can now call function adc to read the voltage drop at the thermocouple
The voltage reading will be read by the MCP as a value between 0 (0V)to 1023 (3.3V) *)
(* Analog Channel = 0, ClockPin = 18, In = 23, Out =24, CS = 25 *)
adc[0, 18, 23, 24, 25]

(*The following function translates the voltage reading to temperature in Celsius*)
temp[channel_] := 

Module[{R2 = 56000, a = -0.0913946, b = 6.80504, R1, 
 x = adc[channel, 18, 23, 24, 25]},
 R1 = (1024 - x) R2/x ; Exp[a Log[R1] + b] - 273.15]

(*Function datapoints is used to collect temperature readings in a matrix of length maxPoints. It also controls the relay
 to turn on the crock pot when the temperature reading is below the setpoint and turn it on when above the set point*)

datapoints[myList_List, fn_, maxLength_Integer, setPoint_Integer] := 

Module[{x, val = fn},
 x = Append[myList, {DateList[], fn}];
 If[val < setPoint, DeviceWrite["GPIO", 17 -> 0], 
 DeviceWrite["GPIO", 17 -> 1]];
 If[Length[x] > maxLength, x = Take[x, -maxLength], x]]


(*Using a Chart to establish the setpoint and graph the temperature trend *)


 DateListPlot[Refresh[data = datapoints[data, temp[0], 300, setPoint], 
 UpdateInterval -> 15, TrackedSymbols -> {}], Joined -> True, 
 PlotRange -> {Automatic, {20, 100}}, 
 GridLines -> {Automatic, {setPoint}}], {{setPoint, 60}, 30, 80, 1, 
 Appearance -> "Labeled"}]


Check out Diego giving a demo of the program and relay controller!

Also, if thermocouples aren’t your thing, you can alternatively get your temperature readings using a waterproof digital temperature sensor and following this lovely setup tutorial by Adafruit.

Happy cooking!


BarryK avatar

That’s fantastic. I’m planning on tackling a technically similar project, using the Compute Module to drive a surface mount oven (ex-toaster oven variety) that’s controlled through a web server to allow a user to select profiles and view (and log) reflow metrics etc through a browser. This project gives me more than a good starting point for the software, great job Diego!

meltwater avatar

As it happens using the DS18B20 temperature sensor is featured in next month’s MagPi too. :)

Look forward to trying out the Wolfram demo. I want a temperature controlled coffee mug!

Trixor avatar

Uhm.. just to clearify, don’t you mean a thermistor instead of a thermocouple?
They are very different animals, and you can not use a mcp3008 to read a thermocouple. Thermistors only go between -50 to 200 degrees C. Thermocouples go from -200 to 1400 degrees C.

AndrewS avatar

When I saw the title I was expecting a PID loop rather than a simple on-off loop ;-)

Hope you don’t mind me asking (I’ve not used Wolfram, so can’t tell exactly what the code is doing), but other than the pretty graph is this doing something that you couldn’t do with a simple Python script?

David avatar

I think you are right at the moment (although the thermistor curve fitting is much more elegant in Mathematica). Where I hope the authors are going is to model the temperature response of the food in response to the water temperature, which will be a lot easier in Mathematica.

Jeff avatar

Using simple thermostat on/off code and a crock-pot, I wouldn’t call this sous vide cooking. It my experimenting while making my sous vide setup, my crock-pot had a 10+ min delay between switching the element on and seeing a temperature change. Thus, the water bath temperature would probably overshoot/undershoot a lot with this setup. A PID loop would be much more ideal, and a rice cooker (which I now use) responds much quicker to inputs.

Andrew avatar

Agreed Jeff, the simpler the device the better, some crock-pots are far too complicated for their own good.

May I also add that professional sous vide machines also stir the water to ensure even temperature distribution. This couple be achieved with a small impeller submerged in the water bath.

Ed avatar

Two includes missing in adc.c, probably stripped by the CMS software because they’re between characters. I guess mcp3008.h and gpio.h?

Ed avatar

Ah, there you go. I wrote: “between *less than* and *greater than*” but those got stripped as well. I thought spaces around them would avoid it. Probably best to give the post/comment processing code a look-over!

Comments are closed