This is a brief description of the systems that I use to detect Solar Flares.


I use two receivers , one tuned to the DHO transmitter (23.4kHz)  in Germany, the second tuned to the HWU transmitter (22.6kHz) in central France. These transmitters are used to make contact with submarines located around the world. However, signals only propagate during daytime hours using a channel that is formed between ground and the ionospheric D layer.

The two receivers were built in 2010 from kits supplied by the UKRAA. They are fairly straightforward to build using discreet electronic components rather than more modern microscopic surface mount devices. The receivers were designed by John Cook, a former director of the BAA Radio Astronomy Group. These would make a good second project for someone who has already built a simple electronic kit and is confident to solder neatly and can identify and orientate the components correctly.

I have two loop aerials located in the loft, each is orientated in the direction of the transmitter to maximise signal strength. 

UKRAA VLF Antenna. The antenna is orientated so that the horizontal supporting beam points in the direction (within10 degrees) of the transmitter

There is approximately 10m of RG58 50 ohm coax cable (TV coax would suffice) that connects  each of the antennae to the pair of VLF Receivers located in my home lab.

The cables are terminated with a BNC connector.

Within the very slim box, I have two receiver boards. two tuning units, a 15V power supply liberated from an old laptop, a 15V to 5V voltage converter and an early Raspberry Pi model B that is used for data collection.

All interconnectivity in the receiver unit of the radio connections is by BNC connectors and thin coaxial cable.

Each receiver has an Antenna Tuning Unit (ATU) that is connected between the antenna and the receiver. One of the characteristics of a small multi turn loop aerial is that they have a very narrow effective bandwidth. This means that unless they are tuned to the correct frequency, the antenna will actually reject the wanted signal. The ATU tunes that antenna and 'magnifies' the signal (Q factor) so the receiver has got something to work with. Tuning the ATU can be tricky, but its not an impossible task. ATUs and loop antennas were sourced from the UKRAA.

The ATU comprises of a low cost variable capacitor interconnected with a number of switchable fixed capacitors to provide an adequate tuning range.

The receivers are early versions of the current UKRAA supplied VLF receiver, however, changes have been minimal.

Tuning the receivers is fairly simple, only requiring a digital or analogue multi meter and the process is described in the manual that can be downloaded from the UKRAA website.

The output from each of the receivers is an analogue voltage between about 0.5V and 5V. (Note: the Raspberry Pi ADC can only cope with a maximum of 3V. To reduce the output from 5V to 3V, I simply reduced the gain of the receivers).

I use a Raspberry Pi Model B - about 12 years old (maybe more) - to log data. These often appear on a well know internet auction site and can be 'won' with a bid of a few pounds. Although they are full computers with operating system in their own right, they are straightforward to maintain (although the Linux learning curve can be a little steep), but they are also easy to program using the Python3 interpretative programming language. There is a huge amount of  support available from a number of groups on the internet along with the BAA Radio Astronomy group forum on the forum.

There are two problems with the Pi though, it needs a 5V supply and there is no Analogue input. The first problem is easily addressed using a voltage converter that costs about £5. The second is resolved with a a 'bolt-on' Analogue to Digital Converter (ADC) that I also use on my magnetometer. See this article on constructing an ADC got this project.

That is basically how the hardware hangs together. You don't need two receivers, however due to the different distances from my observatory to the transmitters the signals received may vary considerably.

The following trace demonstrates this. It was captured on 20231105. 

The flare that was detected at 11:40 UTC was detected on both receivers. The flare at 14:20UTC was only detected on the Rosnay (HWU) receiver, probably because dusk had fallen in Germany and the D layer had diminished. Note the interference, probably caused by my fridge freezer power supply. Radio interference is an annoying side effect of radio reception, in much the same way that sky glow interference from man made sources is an annoyance to visual astronomers.


As mentioned above, all the code is written in Python3.

This is the Python3 script that runs on the VLF Receiver Raspberry Pi.

import datetime
import time
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn


# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)

# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D24) # was D.22

# create the mcp object
mcp = MCP.MCP3008(spi, cs)

# create an analog input channel on pin 0 and 1
chan0 = AnalogIn(mcp, MCP.P0)
chan1 = AnalogIn(mcp, MCP.P1)



while True:

        if i < 5:
                rx1array[i] = chan0.voltage
                rx2array[i] = chan1.voltage
                rx1array[i] = chan0.voltage
                rx2array[i] = chan1.voltage


        chan0sum = (rx1array[0]+rx1array[1]+rx1array[2]+rx1array[3]+rx1array[4])/5
        chan1sum = (rx2array[0]+rx2array[1]+rx2array[2]+rx2array[3]+rx2array[4])/5

        # get date and time
        date =
#       print (date)
        filedate = (date.strftime("%Y") + date.strftime("%m") + date.strftime("%d"))
#       print (filedate)
        filepath = "/home/pi/data/"
        filename="vlf2_" + filedate + ".csv"
        file = open(filepath+filename,"a")
        filetime = (date.strftime("%H") + date.strftime("%M") + date.strftime("%S"))
        filetime2 = (date.strftime("%H") + ":" + date.strftime("%M") + ":" + date.strftime("%S"))

        now =
        midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
        seconds = (now - midnight).seconds

        decimalhrs = seconds /3600

        file.write(filedate + "," + str(decimalhrs) + "," + str(((chan0sum))) + "," + str(((chan1sum))) + "," + str(chan0.value) + "," + str(chan1.value) + "\n")


The second script runs on a small Linux Server (it could be a Windows PC with minor formatting changes - for example file and path names).

This collects the data from the VLF receiver PC using a SFTP connection, formats the data and produces the graph.

#import sys
import pysftp
import datetime
import numpy as np
import matplotlib.pyplot as plt
import time
import os

date =
filedate = (date.strftime("%Y") + date.strftime("%m") + date.strftime("%d"))

filepath = "/home/pi/data/"
filepath2 = "/home/martyn/data/vlf2/"

filename="vlf2_" + filedate + ".csv"

fullpath = filepath2 + filename
os.chdir(filepath2) # /data/vlf2
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
with pysftp.Connection('', username='username', password='xxxxxx') as sftp:

    with ('data'):
#        sftp.get(fullpath)

filedate = (date.strftime("%Y") + date.strftime("%m") + date.strftime("%d"))
filedate2 = (date.strftime("%Y") + "-" + date.strftime("%m") + "-" + date.strftime("%d"))

filename2="vlf2_" + filedate + ".csv"
fullpath = filepath2 + filename2
filetime = (date.strftime("%H") + ":" + date.strftime("%M")) + "UTC"

gmonth = int(date.strftime("%m"))

vlf2data = np.loadtxt(fullpath, delimiter=",")


#draw the graph
fig, ax = plt.subplots(sharex=True, figsize=(12, 6))

charttitle = filedate2 + " " + filetime + " -- BAA RAG VLF Receivers -- Oak Bank Observatory Willaston UK"
ax.plot (timedata,rx1data, color='blue', label = 'Rx1 DHO 23.4kHz',lw=1)
ax.plot (timedata,rx2data, color='red',  label = 'Rx2 HWU 22.6kHz',lw=1)

if gmonth < 3 or gmonth > 10:
#       print("1 ",gmonth)
        if gmonth < 5 or gmonth > 8:
#               print("2 ", gmonth)



plt.xlabel("Time UTC (Hours)")
plt.ylabel("Signal Strength")
plt.grid(True, which='both')
image = "vlf2"+filedate+".png"

There is a 3rd script that copies the image to the webserver but that is not really important here.