Earth, Air, Water, and Ice.

In my attempts at Ice Storage Heat Source popularization I have been facing one big challenge: How can you – succinctly, using pictures – answer questions like:

How much energy does the collector harvest?

or

What’s the contribution of ground?

or

Why do you need a collector if the monthly performance factor just drops a bit when you turned it off during the Ice Storage Challenge?

The short answer is that the collector (if properly sized in relation to tank and heat pump) provides for about 75% of the ambient energy needed by the heat pump in an average year. Before the ‘Challenge’ in 2015 performance did not drop because the energy in the tank had been filled up to the brim by the collector before. So the collector is not a nice add-on but an essential part of the heat source. The tank is needed to buffer energy for colder periods; otherwise the system would operate like an air heat pump without any storage.

I am calling Data Kraken for help to give me more diagrams.

There are two kinds of energy balances:

1) From the volume of ice and tank temperature the energy still stored in the tank can be calculated. Our tank ‘contains’ about 2.300 kWh of energy when ‘full’. Stored energy changes …

  • … because energy is extracted from the tank or released to it via the heat exchanger pipes traversing it.
  • … and because heat is exchanged with the surrounding ground through the walls and the floor of the tank.

Thus the contribution of ground can be determined by:

Change of stored energy(Ice, Water) =
Energy over ribbed pipe heat exchanger + Energy exchanged with ground

2) On the other hand, three heat exchangers are serially connected in the brine circuit: The heat pump’s evaporator, the solar air collector, and the heat exchanger in the tank. .

Both of these energy balances are shown in this diagram (The direction of arrows indicates energy > 0):

Energy sources, transfer, storage - sign conventions

The heat pump is using a combined heat source, made up of tank and collector, so …

Ambient Energy for Heat Pump = -(Collector Energy) + Tank Energy

The following diagrams show data for the season containing the Ice Storage Challenge:

Season 2014 - 2015: Monthly Energy Balances: Energy Sources, Transfer, Storage

From September to January more and more ambient energy is needed – but also the contribution of the collector increases! The longer the collector is on in parallel with the heat pump, the more energy can be harvested from air (as the temperature difference between air and brine is increased).

As long as there is no ice the temperature of the tank and the brine inlet temperature follow air temperature approximately. But if air temperature drops quickly (e.g. at the end of November 2014), the tank is still rather warm in relation to air and the collector cannot harvest much. Then the energy stored in the tank drops and energy starts to flow from ground to the tank.

2014-09-01 - 2015-05-15: Temperatures and ice formation

2014-09-01 - 2015-05-15: Daily Energy Balances: Energy Sources, Transfer, Storage

On Jan 10 an anomalous peak in collector energy is visible: Warm winter storm Felix gave us a record harvest exceeding the energy needed by the heat pump! In addition to high ambient temperatures and convection (wind) the tank temperature remained low while energy was used for melting ice.

On February 1, we turned off the collector – and now the stored energy started to decline. Since the collector energy in February is zero, the energy transferred via the heat exchanger is equal to the ambient energy used by the heat pump. Ground provided for about 1/3 of the ambient energy. Near the end of the Ice Storage Challenge (mid of March) the contribution of ground was increasing while the contribution of latent energy became smaller and smaller: Ice hardly grew anymore, allegedly after the ice cube has ‘touched ground’.

Mid of March the collector was turned on again: Again (as during the Felix episode) harvest is high because the tank remains at 0°C. The energy stored in the tank is replenished quickly. Heat transfer with ground is rather small, and thus the heat exchanger energy is about equal to the change in energy stored.

At the beginning of May, we switched to summer mode: The collector is turned off (by the control system) to keep tank temperature at 8°C as long as possible. This temperature is a trade-off between optimizing heat pump performance and keeping some energy for passive cooling. The energy available for cooling is reduced by the slow flow of heat from ground to the tank.

My Data Kraken – a Shapeshifter

I wonder if Data Kraken is only used by German speakers who translate our hackneyed Datenkrake – is it a word like eigenvector?

Anyway, I need this animal metaphor, despite this post is not about facebook or Google. It’s about my personal Data Kraken – which is a true shapeshifter like all octopuses are:

(… because they are spineless, but I don’t want to over-interpret the metaphor…)

Data Kraken’s shapeability is a blessing, given ongoing challenges:

When the Chief Engineer is fighting with other intimidating life-forms in our habitat, he focuses on survival first and foremost … and sometimes he forgets to inform the Chief Science Officer about fundamental changes to our landscape of sensors. Then Data Kraken has to be trained again to learn how to detect if the heat pump is on or off in a specific timeslot. Use the signal sent from control to the heat pump? Or to the brine pump? Or better use brine flow and temperature difference?

It might seem like a dull and tedious exercise to calculate ‘averages’ and other performance indicators that require only very simple arithmetics. But with the exception of room or ambient temperature most of the ‘averages’ just make sense if some condition is met, like: The heating water inlet temperature should only be calculated when the heating circuit pump is on. But the temperature of the cold water, when the same floor loops are used for cooling in summer, should not be included in this average of ‘heating water temperature’. Above all, false sensor readings, like 0, NULL or any value (like 999) a vendor chooses to indicate as an error, have to be excluded. And sometimes I rediscover eternal truths like the ratio of averages not being equal to the average of ratios.

The Chief Engineer is tinkering with new sensors all the time: In parallel to using the old & robust analog sensor for measuring the water level in the tank…

Level sensor: The old way

… a multitude of level sensors was evaluated …

Level sensors: The precursors

… until finally Mr. Bubble won the casting …

blubber-messrohr-3

… and the surface level is now measured via the pressure increasing linearly with depth. For the Big Data Department this means to add some new fields to the Kraken database, calculate new averages … and to smoothly transition from the volume of ice calculated from ruler readings to the new values.

Change is the only constant in the universe, paraphrasing Heraclitus [*]. Sensors morph in purpose: The heating circuit, formerly known (to the control unit) as the radiator circuit became a new wall heating circuit, and the radiator circuit was virtually reborn as a new circuit.

I am also guilty of adding new tentacles all the time, too, herding a zoo of meters added in 2015, each of them adding a new log file, containing data taken at different points of time in different intervals. This year I let Kraken put tentacles into the heat pump:

Data Kraken: Tentacles in the heat pump!

But the most challenging data source to integrate is the most unassuming source of logging data: The small list of the data that The Chief Engineer had recorded manually until recently (until the advent of Miss Pi CAN Sniffer and Mr Bubble). Reason: He had refused to take data at exactly 00:00:00 every single day, so learned things I never wanted to know about SQL programming languages to deal with the odd time intervals.

To be fair, the Chief Engineer has been dedicated at data recording! He never shunned true challenges, like a legendary white-out in our garden, at the time when measuring ground temperatures was not automated yet:

The challenge

White Out

Long-term readers of this blog know that ‘elkement’ stands for a combination of nerd and luddite, so I try to merge a dinosaur scripting approach with real-world global AI Data Krakens’ wildest dream: I wrote scripts that create scripts that create scripts [[[…]]] that were based on a small proto-Kraken – a nice-to-use documentation database containing the history of sensors and calculations.

The mutated Kraken is able to eat all kinds of log files, including clients’ ones, and above all, it can be cloned easily.

I’ve added all the images and anecdotes to justify why an unpretentious user interface like the following is my true Christmas present to myself – ‘easily clickable’ calculated performance data for days, months, years, and heating seasons.

Data Kraken: UI

… and diagrams that can be changed automatically, by selecting interesting parameters and time frames:

Excel for visualization of measurement data

The major overhaul of Data Kraken turned out to be prescient as a seemingly innocuous firmware upgrade just changed not only log file naming conventions and publication scheduled but also shuffled all the fields in log files. My Data Kraken has to be capable to rebuild the SQL database from scratch, based on a documentation of those ever changing fields and the raw log files.

_________________________________

[*] It was hard to find the true original quote for that, as the internet is cluttered with change management coaches using that quote, and Heraclitus speaks to us only through secondary sources. But anyway, what this philosophy website says about Heraclitus applies very well to my Data Kraken:

The exact interpretation of these doctrines is controversial, as is the inference often drawn from this theory that in the world as Heraclitus conceives it contradictory propositions must be true.

In my world, I also need to deal with intriguing ambiguity!

Same Procedure as Every Autumn: New Data for the Heat Pump System

October – time for updating documentation of the heat pump system again! Consolidated data are available in this PDF document.

In the last season there were no special experiments – like last year’s Ice Storage Challenge or using the wood stove. Winter was rather mild, so we needed only ~16.700kWh for space heating plus hot water heating. In the coldest season so far – 2012/13 – the equivalent energy value was ~19.700kWh. The house is located in Eastern Austria, has been built in the 1920s, and has 185m2 floor space since the last major renovation.

(More cross-cultural info:  I use thousands dots and decimal commas).

The seasonal performance factor was about 4,6 [kWh/kWh] – thus the electrical input energy was about 16.700kWh / 4,6 ~ 3.600kWh.

Note: Hot water heating is included and we use flat radiators requiring a higher water supply temperature than the floor heating loops in the new part of the house.

Heating season 2015/2016: Performance data for the 'ice-storage-/solar-powered' heat pump system

Red: Heating energy ‘produced’ by the heat pump – for space heating and hot water heating. Yellow: Electrical input energy. Green: Performance Factor = Ratio of these energies.

The difference of 16.700kWh – 3.600kWh = 13.100kWh was provided by ambient energy, extracted from our heat source – a combination of underground water/ice tank and an unglazed ribbed pipe solar/air collector.

The solar/air collector has delivered the greater part of the ambient energy, about 10.500kWh:

Heating season 2015/2016: Energy harvested from air by the collector versus heating-energy

Energy needed for heating per day (heat pump output) versus energy from the solar/air collector – the main part of the heat pump’s input energy. Negative collector energies indicate passive cooling periods in summer.

Peak Ice was 7 cubic meters, after one cold spell of weather in January:

Heating season 2015/2016: Temperature of ambient air, water tank (heat source) and volume of water frozen in the tank.

Ice is formed in the water tank when the energy from the collector is not sufficient to power the heat pump alone, when ambient air temperatures are close to 0°C.

Last autumn’s analysis on economics is still valid: Natural gas is three times as cheap as electricity but with a performance factor well above three heating costs with this system are lower than they would be with a gas boiler.

Is there anything that changed gradually during all these years and which does not primarily depend on climate? We reduced energy for hot tap water heating – having tweaked water heating schedule gradually: Water is heated up once per day and as late as possible, to avoid cooling off the hot storage tank during the night.

We have now started the fifth heating season. This marks also the fifth anniversary of the day we switched on the first ‘test’ version 1.0 of the system, one year before version 2.0.

It’s been about seven years since first numerical simulations, four years since I have been asked if I was serious in trading in IT security for heat pumps, and one year since I tweeted:

Hacking My Heat Pump – Part 2: Logging Energy Values

In the last post, I showed how to use Raspberry Pi as CAN bus logger – using a test bus connected to control unit UVR1611. Now I have connected it to my heat pump’s bus.

Credits for software and instructions:

Special thanks to SK Pang Electronics who provided me with CAN boards for Raspberry Pi after having read my previous post!!

CAN boards for Raspberry Pi, by SK Pang

CAN extension boards for Raspberry Pi, by SK Pang. Left: PiCAN 2 board (40 GPIO pins), right: smaller, retired PiCAN board with 26 GPIO pins – the latter fits my older Pi. In contrast to the board I used in the first tests, these have also a serial (DB9) interface.

Wiring CAN bus

We use a Stiebel-Eltron WPF 7 basic heat pump installed in 2012. The English website now refers to model WPF 7 basic s.

The CAN bus connections described in the German manual (Section 12.2.3) and the English manual (Wiring diagram, p.25) are similar:

Stiebel-Eltron WPF 7 basic - CAN bus connections shown in German manual

CAN bus connections inside WPF 7 basic heat pump. For reference, see the description of the Physical Layer of the CAN protocol. Usage of the power supply (BUS +) is optional.

H, L and GROUND wires from the Pi’s CAN board are connected to the respective terminals inside the heat pump. I don’t use the optional power supply as the CAN board is powered by Raspberry Pi, and I don’t terminate the bus correctly with 120 Ω. As with the test bus, wires are rather short and thus have low resistance.

Stiebel-Eltron WPF 7 basic - CAN bus connections inside the heat pump, cable from Raspberry Pi connected.

Heat pump with cover removed – CAN High (H – red), Low (L – blue), and Ground (yellow) are connected. The CAN cable is a few meters long and connects to the Raspberry Pi CAN board.

In the first tests Raspberry Pi had the privilege to overlook the heat pump room as the top of the buffer tank was the only spot the WLAN signal was strong enough …

Raspberry Pi, on top of the buffer tank

Typical, temporary nerd’s test setup.

… or I used a cross-over ethernet cable and a special office desk:

Working on the heat pump - Raspberry Pi adventures

Typical, temporary nerd’s workplace.

Now Raspberry Pi has its final position on the ‘organic controller board’, next to control unit UVR16x2 – and after a major upgrade to both LAN and WLAN all connections are reliable.

Raspberry Pi with PiCAN board from SK Pang and UVR16x2

Raspberry Pi with PiCAN board from SK Pang and UVR16x2 control unit from Technische Alternative (each connected to a different CAN bus).

Bringing up the interface

According to messpunkt.org the bit rate of Stiebel-Eltron’s bus is 20000 bit/s; so the interface is activated with:

sudo ip link set can0 type can bitrate 20000
sudo ifconfig can0 up

Watching the idle bus

First I was simply watching with sniffer Wireshark if the heat pump says anything without being triggered. It does not – only once every few minutes there are two packets. So I need to learn to talk to it.

Learning about CAN communications

SK Pang provides an example of requesting data using open source tool cansend: The so-called CAN ID is followed by # and the actual data. This CAN ID refers to an ‘object’ – a set of properties of the device, like the set of inputs or outputs – and it can contain also the node ID of the device on the bus. There are many CAN tutorials on the net, I found this (German) introduction and this English tutorial very useful.

I was able to follow the communications of the two nodes in my test bus as I knew their node numbers and what to expect – the data logger would ask the controller for a set of configured sensor outputs every minute. Most packets sent by either bus member are related to object 480, indicating the transmission of a set of values (Process Data Exchange Objects, PDOs. More details on UVR’s CAN communication, in German)

Network trace on test CAN bus: UVR1611 and BL-NET

Sniffing test CAN bus – communication of UVR1611 (node no 1) and logger BL-NET (node number 62 = be). Both devices use an ID related to object ID 480 plus their respective node number, as described here.

So I need to know object ID(s) and properly formed data values to ask the heat pump for energy readings – without breaking something by changing values.

Collecting interesting heat pump parameters for monitoring

I am very grateful for Jürg’s CAN tool can_scan that allow for querying a Stiebel-Eltron heat pump for specific values and also for learning about all possible parameters (listed in so-called Elster tables).

In order to check the list of allowed CAN IDs used by the heat pump I run:

./can_scan can0 680

can0 is the (default) name of the interface created earlier and 680 is my (the sender’s) CAN ID, one of the IDs allowed by can_scan.

Start of output:

elster-kromschroeder can-bus address scanner and test utility
copyright (c) 2014 Jürg Müller, CH-5524

scan on CAN-id: 680
list of valid can id's:

  000 (8000 = 325-07)
  180 (8000 = 325-07)
  301 (8000 = 325-07)
  480 (8000 = 325-07)
  601 (8000 = 325-07)

In order to investigate available values and their meaning I run can_scan for each of these IDs:

./can_scan can0 680 180

Embedded below is part of the output, containing some of the values (and /* Comments */). This list of parameters is much longer than the list of values available via the display on the heat pump!

I am mainly interested in metered energies and current temperatures of the heat source (brine) and the ‘environment’ – to compare these values to other sensors’ output:

elster-kromschroeder can-bus address scanner and test utility
copyright (c) 2014 Jürg Müller, CH-5524

0001:  0000  (FEHLERMELDUNG  0)
0003:  019a  (SPEICHERSOLLTEMP  41.0)
0005:  00f0  (RAUMSOLLTEMP_I  24.0)
0006:  00c8  (RAUMSOLLTEMP_II  20.0)
0007:  00c8  (RAUMSOLLTEMP_III  20.0)
0008:  00a0  (RAUMSOLLTEMP_NACHT  16.0)
0009:  3a0e  (UHRZEIT  14:58)
000a:  1208  (DATUM  18.08.)
000c:  00e9  (AUSSENTEMP  23.3) /* Ambient temperature */
000d:  ffe6  (SAMMLERISTTEMP  -2.6)
000e:  fe70  (SPEICHERISTTEMP  -40.0)
0010:  0050  (GERAETEKONFIGURATION  80)
0013:  01e0  (EINSTELL_SPEICHERSOLLTEMP  48.0)
0016:  0140  (RUECKLAUFISTTEMP  32.0) /* Heating water return temperature */
...
01d4:  00e2  (QUELLE_IST  22.6) /* Source (brine) temperature */
...
/* Hot tap water heating energy MWh + kWh */
/* Daily totaly */   
092a:  030d  (WAERMEERTRAG_WW_TAG_WH  781)
092b:  0000  (WAERMEERTRAG_WW_TAG_KWH  0)
/* Total energy since system startup */
092c:  0155  (WAERMEERTRAG_WW_SUM_KWH  341)
092d:  001a  (WAERMEERTRAG_WW_SUM_MWH  26)
/* Space heating energy, MWh + kWh */
/* Daily totals */
092e:  02db  (WAERMEERTRAG_HEIZ_TAG_WH  731)
092f:  0006  (WAERMEERTRAG_HEIZ_TAG_KWH  6)
/* Total energy since system startup */
0930:  0073  (WAERMEERTRAG_HEIZ_SUM_KWH  115)
0931:  0027  (WAERMEERTRAG_HEIZ_SUM_MWH  39)

Querying for one value

The the heating energy to date in MWh corresponds to index 0931:

./can_scan can0 680 180.0931

The output of can_scan already contains the sum of the MWh (0931) and kWh (0930) values:

elster-kromschroeder can-bus address scanner and test utility
copyright (c) 2014 Jürg Müller, CH-5524

value: 0027  (WAERMEERTRAG_HEIZ_SUM_MWH  39.115)

The network trace shows that the logger (using ID 680) queries for two values related to ID 180 – the kWh and the MWh part:

Network trace on heat pump's CAN bus: Querying for space heating energy to date.

Network trace of Raspberry Pi CAN logger (ID 680) querying CAN ID 180. Since the returned MWh value is the sum of MWh and kWh value, two queries are needed. Detailed interpretation of packets in the text below.

Interpretation of these four packets – as explained on Jürg’s website here and here in German:

00 00 06 80 05 00 00 00 31 00 fa 09 31  
00 00 01 80 07 00 00 00 d2 00 fa 09 31 00 27
00 00 06 80 05 00 00 00 31 00 fa 09 30 
00 00 01 80 07 00 00 00 d2 00 fa 09 30 00 73
|---------| ||          |---| || |---| |---|
1)          2)          3)    4) 5)    6)

1) CAN-ID used by the sender: 180 or 680 
2) No of bytes of data - 5 for queries, 8 for replies
3) CAN ID of the communications partner and type of message. 
For queries the second digit is 1. 
Pattern: n1 0m with n = 180 / 80 = 3 (hex) and m = 180 mod 7 = 0 
(hex) Partner ID = 30 * 8 (hex) + 00 = 180 
Responses follow a similar pattern using second digit 2: 
Partner ID is: d0 * 8 + 00 = 680 
4) fa indicates that the Elster index no is greater equal ff. 
5) Index (parameter) queried for: 0930 for kWh and 0931 for MWh
6) Value returned 27h=39,73h=115

I am not sure which node IDs my logger and the heat pump use as the IDs. 180 seems to be an object ID without node ID added while 301 would refer to object ID + node ID 1. But I suppose with two devices on the bus only, and one being only a listener, there is no ambiguity.

Logging script

I found all interesting indices listed under CAN ID 180; so am now looping through this set once every three minutes with can_scan, cut out the number, and add it to a new line in a text log file. The CAN interfaces is (re-)started every time in case something happens, and the file is sent to my local server via FTP.

Every month a new log file is started, and log files – to be imported into my SQL Server  and processed as log files from UVR1611 / UVR16x2, the PV generator’s inverter, or the smart meter.

(Not the most elegant script – consider it a ‘proof of concept’! Another option is to trigger the sending of data with can_scan and collect output via can_logger.)

Interesting to-be-logged parameters are added to a ‘table’ – a file called indices:

0016 RUECKLAUFISTTEMP
01d4 QUELLE_IST
01d6 WPVORLAUFIST
091b EL_AUFNAHMELEISTUNG_WW_TAG_KWH
091d EL_AUFNAHMELEISTUNG_WW_SUM_MWH
091f EL_AUFNAHMELEISTUNG_HEIZ_TAG_KWH
0921 EL_AUFNAHMELEISTUNG_HEIZ_SUM_MWH
092b WAERMEERTRAG_WW_TAG_KWH
092f WAERMEERTRAG_HEIZ_TAG_KWH
092d WAERMEERTRAG_WW_SUM_MWH
0931 WAERMEERTRAG_HEIZ_SUM_MWH
000c AUSSENTEMP
0923 WAERMEERTRAG_2WE_WW_TAG_KWH
0925 WAERMEERTRAG_2WE_WW_SUM_MWH
0927 WAERMEERTRAG_2WE_HEIZ_TAG_KWH
0929 WAERMEERTRAG_2WE_HEIZ_SUM_MWH

Script:

# Define folders
logdir="/CAN_LOGS"
scriptsdir="/CAN_SCRIPTS"
indexfile="$scriptsdir/indices"

# FTP parameters
ftphost="FTP_SERVER"
ftpuser="FTP_USER"
ftppw="***********"

# Exit if scripts not found
if ! [ -d $scriptsdir ] 
then
    echo Directory $scriptsdir does not exist!
    exit 1
fi

# Create log dir if it does not exist yet
if ! [ -d $logdir ] 
then
    mkdir $logdir
fi

sleep 5

echo ======================================================================

# Start logging
while [ 0 -le 1 ]
do

# Get current date and start new logging line
now=$(date +'%Y-%m-%d;%H:%M:%S')
line=$now
year=$(date +'%Y')
month=$(date +'%m')
logfile=$year-$month-can-log-wpf7.csv
logfilepath=$logdir/$logfile

# Create a new file for every month, write header line
# Create a new file for every month
if ! [ -f $logfilepath ] 
then
    headers="Datum Uhrzeit"
    while read indexline
    do 
        header=$(echo $indexline | cut -d" " -f2) 
        headers+=";"$header
    done < $indexfile ; echo "$headers" > $logfilepath 
fi

# (Re-)start CAN interface
    sudo ip link set can0 type can bitrate 20000
    sudo ip link set can0 up

# Loop through interesting Elster indices
while read indexline
do 
    # Get output of can_scan for this index, search for line with output values
    index=$(echo $indexline | cut -d" " -f1)
    value=$($scriptsdir/./can_scan can0 680 180.$index | grep "value" | replace ")" "" | grep -o "\<[0-9]*\.\?[0-9]*$" | replace "." ",")     
    echo "$index $value"     

    # Append value to line of CSV file     
    line="$line;$value" 
done < $indexfile ; echo $line >> $logfilepath

# echo FTP log file to server
ftp -n -v $ftphost << END_SCRIPT
ascii
user $ftpuser $ftppw
binary
cd RPi
ls
lcd $logdir
put $logfile
ls
bye
END_SCRIPT

echo "------------------------------------------------------------------"

# Wait - next logging data point
sleep 180

# Runs forever, use Ctrl+C to stop
done

In order to autostart the script I added a line to the rc.local file:

su pi -c '/CAN_SCRIPTS/pkt_can_monitor'

Using the logged values

In contrast to brine or water temperature heating energies are not available on the heat pump’s CAN bus in real-time: The main MWh counter is only incremented once per day at midnight. Then the daily kWh counter is added to the previous value.

Daily or monthly energy increments are calculated from the logged values in the SQL database and for example used to determine performance factors (heating energy over electrical energy) shown in our documentation of measurement data for the heat pump system.

Hacking My Heat Pump – Part 1: CAN Bus Testing with UVR1611

In the old times, measuring data manually sometimes meant braving the elements:

White-Out!

White-Out in winter 2012/13! The barely visible wall is the solar/air collector of our heat pump system.

Measuring ground temperature in different depth ... slowly.

Measuring ground temperature in different depths.

Now, nearly all measurements are automated:

Online schematic of the heatpump system, showing the temperature and flow sensors needed for control, and a few sensors needed for research (radiation, ground temperature). Screenshot from CMI/UVR1611/UVR16x

Online schematic of the heat pump system, showing the temperature and flow sensors needed for control, and a few of the sensors needed for monitoring only (radiation, ground temperature). Screenshot from CMI/UVR1611/UVR16x, Details on system’s operation in this post.

In order to calculate the seasonal performance factor of the heat pump system we have still used the ‘official’ energy reading provided by the heat pump’s display.

Can’t this be automated, too?

Our Stiebel-Eltron WPF7 basic is a simple brine/water heat pump without ‘smart’ features. Our control units turns it on and off via a latch contact.

But there are two interesting interfaces:

  • An optical interface to connect a service PC.
  • Wired connections to an internal CAN bus – a simple fieldbus used for example in vehicles.

We picked option 2 as it does not require an optical device to read off data. Our control unit also uses CAN bus, and we have test equipment for wired CAN connections.

I always want to use what we already have, and I had a Raspberry Pi not yet put into ‘productive’ use. As usual, you find geeks online who did already what you plan: Reading off CAN bus data provided by a Stiebel-Eltron heat pump using a Raspberry Pi.

In this first post, I am covering the test hardware setup. Before connecting to the heat pump I wanted to test with CAN devices I am familiar with.

Credits

I am indebted to the following sources for information and tools:

On Stiebel-Eltron heat pumps’ CAN bus plus Raspberry Pi

On Raspberry Pi and CAN bus in general / for other applications:

CAN converter

RPi has so-called GPIO pins that let you control devices in the real world. Talking to a CAN device requires an extension board to be connected to these pins.

My challenge: I had the older version – ‘Model B’ – with 26 GPIO pins only. The successor model B Plus had 40 pins. While the pin assignment was not changed, newer CAN extension boards (like this from SK Pang) were too large physically for the old Pi (The older, smaller board from SK Pang had been retired). I was glad to find this small board on ebay.

Edit, 2016-08-24: I replaced the board shown below by SK Pang’s retired PiCAN board – see part 2.

My Pi plus extension board:

Raspberry Pi plus CAN board

CAN extension board connected to the Pi’s GPIO pins and to CAN bus (grey, three wires yellow, red, blue). Black (right) – electrical power, Blue (left): Ethernet. See more info on wiring below in the text.

Wiring the test CAN bus

The image shows the CAN board attached to the Pi, with CAN High, Low, and Ground connected. Following standards, CAN bus needs to be terminated on both ends, using a 120Ω resistor. As our wires are quite short and we had never observed issues with not / falsely terminated short CAN busses so far, we did not add proper termination (BTW: Thanks to ebay seller ZAB for providing the proper resistor!)

In the final setup, the other end of the CAN cable has to be connected to heat pump’s internal bus.

For testing purposes, I am building a CAN bus with three member devices:

  1. Test control unit UVR1611 by Technische Alternative. This test unit does not control anything. A single temperature sensor is connected to check if logging works as expected.
  2. The unit’s data logger BL-NET: The logger and the control unit communicate via CAN bus and logging data can be transferred to a PC via ethernet. For more details on using control units and loggers by Technische Alternative see this post.
  3. My Raspberry Pi plus CAN board – connected to BL-NET.
Test Can bus: UVR1611, BL-NET

Middle: Control unit UVR1611 (box with display), one Pt1000 temperature sensor connected (metal tube, black cable), Top: Data logger BL-NET (white box), connected to UVR1611 and Raspberry PI via CAN bus (grey CAN cables, blue plug). The yellow LAN / ethernet cable is for connecting a test PC.

I am using software WinSol on a PC connected via Ethernet to the data logger – to configure logging (BL-NET’s IP address) and to check if the temperature sensor works. BL-NET is set to log data every minute, so that I am sure that CAN packets are available on the bus often. More on WinSol and BL-NET here.

Activating CAN capabilities

Operating system update: I had first used the Raspberry Pi in 2014 using the Raspbian operating system, and I used a pre-installed SD card. Newer versions of the Raspbian Linux operating system do support CAN interfaces, so I just had to upgrade the kernel, described e.g. in CowFish’s instructions (see Software Installation section)

Operating system config: The CAN interface needs the underlying SPI bus – which has to be activated in the Pi’s configuration. This is described in detail on the blog of board vendor SK Pang.

Setting bit rate and bringing up the CAN interface

In order to check if software has been installed correctly, a virtual CAN interface can be configured as a rehearsal:

sudo modprobe vcan
sudo ip link add vcan0 type vcan
sudo ip link set vcan0 up

This interface is not used, so sniffer software (as Wireshark, see below) will not show any communication.

If a physical CAN interface is activated if no CAN bus is physically connected an error cannot find device can0 is expected.

The critical parameter for the physical CAN bus is the bit rate of the bus. For an existing bus, you need to figure out its bit rate from documentation.

According to messpunkt.org the bit rate for the heat pump’s is 20kbit/s. UVR1611’s bus uses bit rate is 50kbit/s, so the interface is configured with

sudo ip link set can0 type can bitrate 50000
sudo ifconfig can0 up

Troubleshooting wrong bit rate

If this is not configured correctly, you will not get errors but you will simply don’t see any packets. Checking the CAN bus (with erroneously configured bit rate) with

sudo ip -s -d link show can0

showed that CAN state is BUS OFF …

CAN bus error: Wrong bit rate

Inspecting CAN bus performance details, having configured the UVR1611 bus (requiring 50kbit/s) with only 20kbit/s.

… a state the device can enter if there have been too many errors on the bus according to this documentation the CAN protocol family in Linux.

If the bit rate is set to 50000, packets are visible now.

Watching packets flowing by

I’ve installed Wireshark sniffer on the PI…

sudo apt-get install wireshark

… and selected the can0 interface. Packets are flowing, and Wireshark parses them correctly as CAN Protocol!

Sniffing CAN bus packets with RaspBerry Pi

Network trace of CAN communications on the test CAN bus, consisting of UVR1611 and data logger BL-NET (Talking to each other) plus Raspberry Pi as silent sniffer.

If you know ‘how to speak CAN’ other devices on the bus can be polled for measurement values, using tools, like the Jürg’s CAN Progs or SK Pang’s Test tools linked at the bottom of this article.

In the next post in this series I will cover the setup of the Raspberry Pi CAN sniffer for the heat pump’s CAN bus.

>> Continued >> Part 2

Alien Energy

I am sure it protects us not only from lightning but also from alien attacks and EMP guns …

So I wrote about our lightning protection, installed together with our photovoltaic generator. Now our PV generator is operational for 11 months and we have encountered one alien attack, albeit by beneficial aliens.

The Sunny Baseline

This is the electrical output power of our generator – oriented partly south-east, partly south-west – for some selected nearly perfectly cloudless days last year. Even in darkest winter you could fit the 2kW peak that a water cooker or heat pump needs under the curve at noon. We can heat hot water once a day on a really sunny day but not provide enough energy for room heating (monthly statistics here).

PV power over time: Sunny days 2015

Alien Spikes and an Extended Alien Attack

I was intrigued by very high and narrow spikes of output power immediately after clouds had passed by:

PV power over time, data points taken every few seconds.

There are two possible explanations: 1) Increase in solar cell efficiency as the panels cool off while shadowed or 2) ‘focusing’ (refraction) of radiation by the edges of nearby clouds.

Such 4kW peaks lasting only a few seconds wide are not uncommon, but typically they do not show up in our standard logging, comprising 5-minute averages.

There was one notable exception this February: Power surged to more than 4kW which is significantly higher than the output on other sunny days in February. Actually, it was higher than the output on the best ever sunny day last May 11 and as high as the peaks on summer solstice (Aliens are green, of course):

PV power over time: Alien Energy on Feb 11, 2016

Temperature effect and/or ‘focusing’?

On the alien attack day it was cloudy and warmer in the night than on the sunny reference day, February 6. At about 11:30 the sun was breaking through the clouds, hitting rather cool panels:

PV power over time: February 2016 - Output Power and Ambient Temperature

At that day, the sun was lingering right at the edge of clouds for some time, and global radiation was likely to be higher than expected due to the focusing effect.

Global Radiation over time: February 2016

The jump in global radiation at 11:30 is clearly visible in our measurements of radiation. But in addition panels had been heated up before by the peak in solar radiation and air temperature had risen, too. So the different effects cannot be disentangled easily .

Power drops by 0,44% of the rated power per decrease in °C of panel temperature. Our generator has 4,77kW, so power decreases by 21W/°C panel temperature.

At 11:30 power was by 1,3kW higher than power on the normal reference day – the theoretical equivalent of a panel temperature decrease by 62°C. I think I can safely attribute the initial surge in output power to the unusual peak in global radiation only.

At 12:30 output power is lower by 300W on the normal sunny day compared to the alien day. This can partly be attributed to the lower input radiation, and partly to a higher ambient temperature.

But only if input radiation is changing slowly, panel temperature has a simple, linear relationship with input temperature. The sun might be blocked for a very short period – shorter than our standard logging interval of 90s for radiation – and the surface of panels cools off intermittently. It is an interesting optimization problem: By just the right combination of blocking period and sunny period overall output could be maximized.

Re-visiting data from last hot August to add more dubious numbers

Panels’ performance was lower for higher ambient air temperatures …

PV power over time: August 2015 - Output Power and Ambient Temperature

… while global radiation over time was about the same. Actually the enveloping curve was the same, and there were even negative spikes at noon despite the better PV performance:

Global Radiation over time: August 2015

The difference in peak power was about 750W. The panel temperature difference to account for that would have to be about 36°. This is three times the measured difference in ambient temperature of 39°C – 27°C = 12°C. Is this plausible?

PV planners use a worst-case panel temperature of 75°C – for worst-case hot days like August 12, 2015.

Normal Operating Cell Temperature of panels is about 46°C. Normal conditions are: 20°C of ambient air, 800W/m2 solar radiation, and free-standing panels. One panel has an area of about 1,61m2; our generator with 18 panels has 29m2, so 800W/m2 translates to 23kW. Since the efficiency of solar panels is about 16%, 23kW of input generates about 3,7kW output power – about the average of the peak values of the two days in August. Our panels are attached to the roof and not free-standing – which is expected to result in a temperature increase of 10°C.

So we had been close to normal conditions at noon radiation-wise, and if we had been able to crank ambient temperature down to 20°C in August, panel temperature had been about 46°C + 10°C = 56°C.

I am boldly interpolating now, in order to estimate panel temperature on the ‘colder’ day in August:

Air Temperature Panel Temperature Comment
20°C 56°C Normal operating conditions, plus typical temperature increase for well-vented rooftop panels.
27°C 63°C August 1. Measured ambient temperature, solar cell temperature interpolated.
39°C 75°C August 12. Measured ambient temperature.
Panel temperature is an estimate for the worst case.

Under perfectly stable conditions panel temperature would have differed by 12°C, resulting in a difference of only ~ 250W (12°C * 21W/°C).

Even considering higher panel temperatures at the hotter day or a non-linear relationship between air temperature and panel temperature will not easily give you the 35° of temperature difference required to explain the observed difference of 750W.

I think we see aliens at work again:

At about 10:45 global radiation for the cooler day, August 1, starts to fluctuate – most likely even more wildly than we see with the 90s interval. Before 10:45, the difference in output power for the two days is actually more like 200-300W – so in line with my haphazard estimate for steady-state conditions.

Then at noon the ‘focusing’ effect could have kicked in, and panel surface temperature might haved fluctuated between 27°C air temperature minimum and the estimated 63°C. Both of these effects could result in the required additional increase of a few 100W.

Since ‘focusing’ is actually refraction by particles in the thinned out edges of clouds, I wonder if the effect could also be caused by barely visible variations of the density of mist in the sky as I remember the hot period in August 2015 as sweltry and a bit hazy, rather than partly cloudy.

I think it is likely that both beneficial effects – temperature and ‘focusing’ – will always be observed in unison. On February 11 I had the chance to see the effect of focusing only (or traces of an alien spaceship that just exited a worm-hole) for about half an hour.

Wormhole travel as envisioned by Les Bossinas for NASA________________________________

Further reading:

On temperature dependence of PV output power – from an awesome resource on photovoltaics:

On the ‘focusing’ effect:

  • Can You Get More than 100% Solar Energy?
    Note especially this comment – describing refraction, and pointing out that refraction of light can ‘focus’ light that would otherwise have been scattered back into space. This commentator also proposes different mechanism for short spikes in power and increase of power during extended periods (such as I observed on February 11).
  • Edge-of-Cloud Effect

Source for the 10°C higher temperature of rooftop panels versus free-standing ones: German link, p.3: Ambient air + 20°C versus air + 30°C

Temperature Waves and Geothermal Energy

Nearly all of renewable energy exploited today is, in a sense, solar energy. Photovoltaic cells convert solar radiation into electricity, solar thermal collectors heat hot water. Plants need solar power for photosynthesis, for ‘creating biomass’. The motion of water and air is influenced by the fictitious forces caused by the earth’s rotation, but by temperature gradients imposed by the distribution of solar energy as well.

Also geothermal heat pumps with ground loops near the surface actually use solar energy deposited in summer and stored for winter – that’s why I think that ‘geothermal heat pumps’ is a bit of a misnomer.

3-ton Slinky Loop

Collector (heat exchanger) for brine-water heat pumps.

Within the first ~10 meters below the surface, temperature fluctuates throughout the year; at 10m the temperature remains about constant and equal to 10-15°C for the whole year.

Only at higher depths the flow of ‘real’ geothermal energy can be spotted: In the top layer of the earth’s crust the temperatures rises about linearly, at about 3°C (3K) per 100m. The details depend on geological peculiarities, it can be higher in active regions. This is the energy utilized by geothermal power plants delivering electricity and/or heat.

Temperature schematic of inner Earth

Geothermal gradient adapted from Boehler, R. (1996). Melting temperature of the Earth’s mantle and core: Earth’s thermal structure. Annual Review of Earth and Planetary Sciences, 24(1), 15–40. (Wikimedia, user Bkilli1). Geothermal power plants use boreholes a few kilometers deep.

This geothermal energy originates from radioactive decays and from the violent past of the primordial earth: when the kinetic energy of celestial objects colliding with each other turned into heat.

The flow of geothermal energy per area directed to the surface, associated with this gradient is about 65 mW/m2 on continents:

Earth heat flow

Global map of the flow of heat, in mW/m2, from Earth’s interior to the surface. Davies, J. H., & Davies, D. R. (2010). Earth’s surface heat flux. Solid Earth, 1(1), 5-24. (Wikimedia user Bkilli1)

Some comparisons:

  • It is small compared to the energy from the sun: In middle Europe, the sun provides about 1.000 kWh per m2 and year, thus 1.000.000Wh / 8.760h = 144W/m2 on average.
  • It also much lower than the rule-of-thumb power of ‘flat’ ground loop collectors – about 20W/m2
  • The total ‘cooling power’ of the earth is several 1010kW: Would the energy not be replenished by radioactive decay, the earth would lose a some seemingly impressive 1014kWh per year, yet this would result only in a temperature difference of ~10-7°C (This is just a back-of-the-envelope check of orders of magnitude, based on earth’s mass and surface area, see links at the bottom for detailed values).

The constant energy in 10m depth – the ‘neutral zone’ – is about the same as the average temperature of the earth (averaged over one year over the surface of the earth): About 14°C. I will show below that this is not a coincidence: The temperature right below the fluctuating temperature wave ‘driven’ by the sun has to be equal to the average value at the surface. It is misleading to attribute the 10°C in 10m depths to the ‘hot inner earth’ only.

In this post I am toying with theoretical calculations, but in order not so scare readers off too much I show the figures first, and add the derivation as an appendix. My goal is to compare these results with our measurements, to cross-check assumptions for the thermal properties of ground I use in numerical simulations of our heat pump system (which I need for modeling e.g. the expected maximum volume of ice)

I start with this:

  1. The surface temperature varies periodically in a year, and I use maximum, minimum and average temperature from our measurements, (corrected a bit for the mild last seasons). These are daily averages as I am not interested in the daily temperature changes between and night.
  2. A constant geothermal flow of 65 mW/m2 is superimposed to that.
  3. The slow transport of solar energy into ground is governed by a thermal property of ground, called the thermal diffusivity. It describes ‘how quickly’ a lump of heat deposited will spread; its unit is area per time. I use an assumption for this number based on values for soil in the literature.

I am determining the temperature as a function of depth and of time by solving the differential equation that governs heat conduction. This equation tells us how a spatial distribution of heat energy or ‘temperature field’ will slowly evolve with time, given the temperature at the boundary of the interesting part of space in question – in this case the surface of the earth. Fortunately, the yearly oscillation of air temperature is about the simplest boundary condition one could have, so you can calculate the solution analytically.
Another nice feature of the underlying equation is that it allows for adding different solutions: I can just add the effect of the real geothermal flow of energy to the fluctuations caused by solar energy.

The result is a  ‘damped temperature wave’; the temperature varies periodically with time and space: The spatial maximum of temperature moves from the surface to a point below and back: In summer (beginning of August) the measured temperature is maximum at the surface, but in autumn the maximum is found some meters below – heat flows back from ground to the surface then:

Temperature wave propagating through ground near the surface of the earth.

Calculated ground temperature, based on measurements of the yearly variation of the temperature at the surface and an assumption of the thermal properties of ground. Calculated for typical middle European maximum and minimum temperatures.

This figure is in line with the images shown in every textbook of geothermal energy. Since the wave is symmetrical about the yearly average, the temperature in about 10m depth, when the wave has ‘run out’, has to be equal to the yearly average at the surface. The wave does not have much chance to oscillate as it is damped down in the middle of the first period, so the length of decay is much shorter than the wavelength.

The geothermal flow just adds a small distortion, an asymmetry of the ‘wave’. It is seen only when switching to a larger scale.

Temperature wave propagating through ground near the surface of the earth - larger scale.

Some data as in previous plot, just extended to greater depths. The geothermal gradient is about 3°C/100m, the detailed value being calculated from the value of thermal conductivity also used to model the fluctuations.

Now varying time instead of space: The higher the depth, the more time it takes for ground to reach maximum temperature. The lag of the maximum temperature is proportional to depth: For 1m difference in depth it is less than a month.

Temperature wave: Temporal evolution

Temporal change of ground temperature at different depths. The wave is damped, but other simply ‘moving into the earth’ at a constant speed.

Measuring the time difference between the maxima for different depths lets us determine the ‘speed of propagation’ of this wave – its wavelength divided by its period. Actually, the speed depends in a simple way on the thermal diffusivity and the period as I show below.

But this gives me an opportunity to cross-check my assumption for diffusivity: I  need to compare the calculations with the experimentally determined delay of the maximum. We measure ground temperature at different depths, below our ice/water tank but also in undisturbed ground:

Temperature wave - experimental results

Temperature measured with Pt1000 sensors – comparing ground temperature at different depths, and the related ‘lag’. Indicated by vertical dotted lines, the approximate positions of maxima and minima. The lag is about 10-15 days.

The lag derived from the figure is in the same order as the lag derived from the calculation and thus in accordance with my assumed thermal diffusivity: In 70cm depth, the temperature peak is delayed by about two weeks.

___________________________________________________

Appendix: Calculations and background.

I am trying to give an outline of my solution, plus some ‘motivation’ of where the differential equation comes from.

Heat transfer is governed by the same type of equation that describes also the diffusion of gas molecules or similar phenomena. Something lumped together in space slowly peters out, spatial irregularities are flattened. Or: The temporal change – the first derivative with respect to time – is ‘driven’ by a spatial curvature, the second derivative with respect to space.

\frac{\partial T}{\partial t} = D\frac{\partial^{2} T}{\partial x^{2}}

This is the heat transfer equation for a region of space that does not have any sources or sinks of heat – places where heat energy would be created from ‘nothing’ or vanish – like an underground nuclear reaction (or freezing of ice). All we know about the material is covered by the constant D, called thermal diffusivity.

The equation is based on local conservation of energy: The energy stored in a small volume of space can only change if something is created or removed within that volume (‘sources’) or if it flows out of the volume through its surface. This is a very general principles applicable to almost anything in physics. Without sources or sinks, this translates to:

\frac{\partial [energy\,density]}{\partial t} = -\frac{\partial \overrightarrow{[energy\,flow]}}{\partial x}

The energy density [J/m3] stored in a volume of material by heating it up from some start temperature is proportional to temperature, proportionality factors being the mass density ρ [kg/m3] and the specific heat cp [J/kg] of this material. The energy flow per area [W/m2] is typically nearly proportional to the temperature gradient, the constant being heat conductivity κ [W/mK]. The gradient is the first-order derivative in space, so inserting all this we end with the second derivative in space.

All three characteristic constants of the heat conducting material can be combined into one – the diffusivity mentioned before:

D = \frac{\kappa }{\varrho \, c_{p} }

So changes in more than one of these parameters can compensate for each other; for example low density can compensate for low conductivity. I hinted at this when writing about heat conduction in our gigantic ice cube: Ice has a higher conductivity and a lower specific heat than water, thus a much higher diffusivity.

I am considering a vast area of ground irradiated by the sun, so heat conduction will be one-dimensional and temperature changes only along the axis perpendicular to the surface. At the surface the temperature varies periodically throughout the year. t=0 is to be associated with beginning of August – our experimentally determined maximum – and the minimum is observed at the beginning of February.

This assumption is just the boundary condition needed to solve this partial differential equation. The real ‘wavy’  variation of temperature is closed to a sine wave, which makes the calculation also very easy. As a physicist I have trained to used a complex exponential function rather than sine or cosine, keeping in mind that only real part describes the real world. This a legitimate choice, thanks to the linearity of the differential equation:

T(t,x=0) = T_{0} e^{i\omega t}

with ω being the angular frequency corresponding to one year (2π/ω = 1 year).

It oscillates about 0, with an amplitude of half of T0. But after all, the definition of 0°C is arbitrary and – again thanks to linearity – we can use this solution and just add a constant function to shift it to the desired value. A constant does neither change with space or time and thus solves the equation trivially.

If you have more complicated sources or sinks, you would represent those mathematically as a composition of simpler ‘sources’, for each of which you can find a quick solution and then add up add the solutions, again thanks to linearity. We are lucky that our boundary condition consist just of one such simple harmonic wave, and we guess at the solution for all of space, adding a spatial wave to the temporal one.

So this is the ansatz – an educated guess for the function that we hope to solve the differential equation:

T(t,x) = T_{0} e^{i\omega t + \beta x}

It’s the temperature at the surface, multiplied by an exponential function. x is positive and increasing with depth. β is some number we don’t know yet. For x=0 it’s equal to the boundary temperature. Would it be a real, negative number, temperature would decrease exponentially with depth.

The ansatz is inserted into the heat equation, and every differentiation with respect to either space or time just yields a factor; then the exponential function can be cancelled from the heat transfer equation. We end up with a constraint for the factor β:

i\omega = D\beta^{2}

Taking the square root of the complex number, there would be two solutions:

\beta=\pm \sqrt{\frac{\omega}{2D}}(1+i))

β has a real and an imaginary part: Using it in T(x,t) the real part corresponds to exponential ‘decay’ while the imaginary part is an oscillation (similar to the temporal one).

Both real and imaginary parts of this function solve the equation (as any linear combination does). So we take the real part and insert β – only the solution for β with negative sign makes sense as the other one would describe temperature increasing to infinity.

T(t,x) = Re \left(T_{0}e^{i\omega t} e^{-\sqrt{\frac{\omega}{2D}}(1+i)x}\right)

The thing in the exponent has to be dimension-less, so we can express the combinations of constants as characteristic lengths, and insert the definition of ω=2π/τ):

T(t,x) = T_{0} e^{-\frac{x}{l}}cos\left(2\pi\left(\frac {t} {\tau} -\frac{x}{\lambda }\right)\right)

The two lengths are:

  • the wavelength of the oscillation \lambda = \sqrt{4\pi D\tau }
  • and the attenuation length  l = \frac{\lambda}{2\pi} = \sqrt{\frac{D\tau}{\pi}}

So the ratio between those lengths does not depend on the properties of the material and the wavelength is always much shorter than the attenuation length. That’s why there is hardly one period visible in the plots.

The plots have been created with this parameters:

  • Heat conductivity κ = 0,0019 kW/mK
  • Density ρ = 2000 kg/m3
  • Specific heat cp = 1,3 kJ/kgK
  • tau = 1 year = 8760 hours

Thus:

  • Diffusivity D = 0,002631 m2/h
  • Wavelength λ = 17 m
  • Attenuation length l = 2,7 m

The wave (any wave) propagates with a speed v equivalent to wavelength over period: v = λ / tau.

v = \frac{\lambda}{\tau} = \frac{\sqrt{4\pi D\tau}}{\tau} = \sqrt{\frac{4\pi D}{\tau}}

The speed depends only on the period and the diffusivity.

The maximum of the temperature as observed in a certain depth x is delayed by a time equal x over v. Cross-checking our measurements of the temperature T(30cm) and T(100cm), I would thus expect a delay by 0,7m / (17m/8760h) = 360 h = 15 days which is approximately in agreement with experiments (taking orders of magnitude). Note one thing though: Only the square root of D is needed in calculations, so any error I make in assumptions for D will be generously reduced.

I have not yet included the geothermal linear temperature gradient in the calculation. Again we are grateful for linearity: A linear – zero-curvature – temperature profile that does not change with time is also a trivial solution of the equation that can be added to our special exponential solution.

So the full solution shown in the plot is the sum of:

  • The damped oscillation (oscillating about 0°C)
  • Plus a constant denoting the true yearly average temperature
  • Plus a linear decrease with depth, the linear correction being 0 at the surface to meet the boundary condition.

If there would be no geothermal gradient (thus no flow from beneath) the temperature at infinite distance (practically in 20m) would be the same as the average temperature of the surface.

Daily changes could be taken into account by adding yet another solution that satisfies an amendment to the boundary condition: Daily fluctuations of temperatures would be superimposed to the yearly oscillations. The derivation would be exactly the same, just the period is different by a factor of 365. Since the characteristic lengths go with the square root of the period, yearly and daily lengths differ only by a factor of about 19.

________________________________________

Further reading:

Intro to geothermal energy:

A quick intro to geothermal energy.
Where does geothermal energy come from?

Geothermal gradient and energy of the earth:

Earth’s heat energy budget
Geothermal gradient
Radius and mass of earth

These data for bore holes using one scale show the gradient plus the disturbed surface region, with not much of a neutral zone in between.

Theory of Heat Conduction

Heat Transfer Equation on Wikipedia
Textbook on Heat Conduction, available on archive.org in different formats.

I have followed the derivation of temperature waves given in my favorite German physics book on Thermodynamics and Statistics, by my late theoretical physics professor Wilhelm Macke. This page quotes the classic on heat conduction, by Carlslaw and Jäger, plus the main results for the characteristic lengths.