Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Over the last couple weeks whenever I had the time I’d work on creating a little Morse code keyer. After a few different designs I came up with the winner. Basically it just uses a bar of aluminum which rocks on a metal pin. Thumb-screws on each side of the balance point (fulcrum?) can be adjusted to modulate the distance the paddle has to go down to be activated, and how high the paddle goes up when released. A couple springs (one pull-type and one push-type) help give it a good bounce between keys. Two knobs control volume and frequency. I especially like the ability to control the frequency! A capacitor inline with the speaker helps smooth the output a bit too. It’s not professional, but hey – for a couple bucks of parts I made a functional keyer and had fun doing it. Now I guess I should put more time into learning Morse code…

Thoughts from future Scott (August 2019, ten years later)

Wow this is rough! I’m 90% sure this is based on a 555 circuit. lol @ the use of Jenga blocks. It looks like the wire was sourced from cat5 cable. That aluminum slab later became the base and heat sink for an IRF510-based push-pull amplifier.





Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Two hours after getting home from work I’m already basking in the newfound carefreeness thanks to the successful completion of my thesis defense (and graduation requirements). Yesterday I went to SkyCraft, early this morning I posted a schematic diagram of a basic circuit concept for a radio/microphone interface box with tone generating functions, and this afternoon I finished its assembly. It’s hacked together, I know, but it’s just a prototype. What does it do? It’s complicated. It’s basically just an exercise in microchip programming.

Future Scott reacts to this in August, 2019 (10 years later)

LOL! That’s a pipette box! A chip socket was sunk into a plastic enclosure somehow! And that “regulated power supply” is an LM7805 on non-metallic perfboard screwed to two Jenga blocks!

Here’s the little setup with the main control unit and a DC to DC regulated power supply / serial microchip programmer I made.

Here’s the main control box. Notice the “2-way lighted switches” which I described in the previous entry. I found that proper grounding (floating pin prevention) was critical to their proper function. I’m still new to these chips, so I’m learning, but I’m making progress!

Getting a little artsy with my photographs now… this is the core of the device. It’s a picaxe 14m!

This is a 5v regulated power supply I built. The headphone adapter is for easy connection to the serial port. It has a power switch and a program/run switch (allowing use of pin 13, serial out) while still “connected” to the PC.

I’ve slightly improved the connection between my radio’s coax cable to the J-pole antenna I made.

I’m able to get pretty good from this antenna, but it’s probably not likely to do much to my assembly skills (and lack of tuning), and more likely due to the fact that I have an unobstructed view of middle/southern Orlando from the 3rd story of my apartment balcony. I could probably wire up a rubber duck on a stick and get good results with that location! I’ll miss my reception when I move.





Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Instead of using a single op-amp circuit like the previous entries which gave me decent but staticky traces, I decided to build a more advanced ECG circuit documented by Jason Nguyen which used 6 op amps! (I’d only been using one). Luckily I got a few couple LM324 quad op-amps from radioshack ($1.40 each), so I had everything I needed.

The results look great! Noise is almost zero, so true details of the trace are visible. I can now clearly see the PQRST features in the wave. I’ll detail how I did this in a later entry. For now, here are some photos of the little device.

UPDATE: After analyzing ~20 minutes of heartbeat data I found a peculiarity. Technically this could be some kind of noise (a ‘pop’ in the microphone signal), but because this peculiarity happened only once in 20 minutes I’m not ruling out the possibility that this is the first irregular heartbeat I captured with my DIY ECG. Note that single-beat irregularities are common in healthy people, and that this does not alarm me so much as fascinate me.





Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Last night I finished building my DIY ECG as a prototype (I finally got the circuit off the breadboard and onto a plastic sheet). This is a similar circuit to the one used to record data from the last entry (resister values are now identical to the crude circuit described several posts ago). I left-in the crude band-pass filter (made by grounding my primary electrode sensor through a 0.1µF capacitor) because it seemed to help a great deal, and wasn’t hard to implement. I picked up all of my parts (including the LM324 quad op-amp microchip) at RadioShack. Of note, the quad-op-amp is overkill because I’m only using one of the 4 op-amps. Theoretically I could add 3 more electrodes to this circuit (which would allow for multi-sensor recording) but this would require multiple microphone jacks, which isn’t very common. I guess I could use 2 microphone jacks, and differentiate right/left channels.

I made the prototype by drilling holes in a small rectangular piece of a non-conductive plastic material. I picked up a stack of these rectangular sections for a quarter at a local electrical surplus store and they’re perfect for prototyping. The two green wires coming out the left side attach to a power supply (either a plugged in AC->DC transformer, 3 or 4 AA batteries, or even a 9V should work). The blue wires on the right attach to the electrodes I put on my chest. The black wires go to a headphone-jack which I plug into the microphone hole of my PC to record the signal.

This is the back of the device which shows my crummy soldering. I’m a molecular biologist not an electrical engineer. The white/yellow wires correspond to the left/right channels of the microphone connector. I only use the left one (white), but attached the right channel (yellow) to the op-amp just in case I decide to add another sensor later – this is not required.

Here’s the full device: You can see the circuit (note its small size – easy to mount inside of a tictac box or something) with the green wires leading to a power supply, black cable being the microphone connector, and the blue wires leading to electrodes made… from… Fanta… cans…? Yes, in the spirit of rigging electronics (my specialty) I found that surprisingly nice chest electrodes can be made from aluminum soda cans! If you go this route, cut them delicately so you don’t get metal shards in your skin like I did at first. Also, note that you have to firmly scrape each side of the aluminum to get the insulating waxy-plastic stuff off or it just won’t work. I guess it’s coated with something to prevent the soda from tasting like metal. Aluminum rapidly transfers heat and it’s nearly impossible to solder leads onto these pads, so I wrapped a wire (tipped with a bead of solder) with the edge of the aluminum several times and crushed the heck out of it with pliers and it seems to stay on well and make a good connection. Also, before taping these onto your skin, it helps to put a conductive goo on it to make the connection better. I added skin moisturizer to each electrode and taped the gooey electrode directly onto my chest.

I recorded ~20 minutes of data last night with this rig and it looked pretty good. I went to analyze it with Python and it kept crashing! The python script I gave you previously loads the entire wave file into an array of numbers, but with a 20 minute wave file (at over 40,000 samples a second) it is too big for memory. I wrote an updated wave loader which loads large wave files in parts which is much more efficient. It also performs the condensation method at load time. Basically, it loads 100 data points (or whatever deg is set to), averages them, and adds this value to a list. The result is a smoothed trace with a resolution of 400 Hz instead of 40 kHz. I’d test this on the wave file I recorded last night but that’s on my laptop which is in the car and I’ve got to get back to work. Here’s that function:

 def loadWav(fname,deg=100):
     global hz
     w=wave.open(fname)
     nchannel, width, rate, length, comptype, compname = w.getparams()
     print "[%s]
 rate: %d Hz
 frames: %d
 length: %.02f sec" %
           (fname, rate, length, float(length)/rate)
     hz=rate/deg
     chunks=int(length/deg)
     data=[]
     for i in range(chunks):
         if i%7777==0:
             print "processing chunk %d of %d (%0.02f%%)" %
                   (i,chunks,100.0*i/chunks)
         vals = struct.unpack("%sh" %deg,w.readframes(deg))
         data.append(sum(vals)/float(deg))
     print "complete!"
     return data




Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Would I rather design circuits or software? I’m a software guy (or at lesat I know more about software than circuits) so I’d rather record noisy signals and write software to eliminate the noise, rather than assembling circuits to eliminate the noise in hardware. In the case of my DIY ECG machine, I’d say I’ve done a surprisingly good job of eliminating noise using software. Most DIY ECG circuits on the net use multiple op-amps and filters to do this. Instead of all that fancy stuff, I made a crude circuit (a single op-amp and two resisters) that is capable of record my ECG and filtered it in software. The output is pretty good!

The first step in removing noise is understanding it. Most of the noise in my signal came from sine waves caused by my electrodes picking up radiated signals in the room. Since this type of interference is consistent through the entire recording, power-spectral analysis could be applied to determine the frequencies of the noise so I could selectively block them out. I used the fast Fourier transform algorithm (FFT) on the values to generate a plot of the spectral components of my signal (mostly noise) seen as sharp peaks. I manually band-stopped certain regions of the spectrum that I thought were noise-related (colored bands). This is possible to do electronically with a more complicated circuit, but is interesting to do in software. I think performed an inverse FFT on the trace. The result was a trace with greatly reduced noise. After a moving window smoothing algorithm was applied the signal was even better! Note that I recorded the WAV file with “sound recorder” (not GoldWave) and did all of the processing (including band-pass filtering) within Python.

The ECG came out better than expected! The graph above shows the power spectral analysis with band-stop filters applied at the colored regions. Below is the trace of the original signal (light gray), the inverse-FFT-filtered trace (dark gray), and the smoothed filtered trace (black) – the final ECG signal I intend to use.

This is a magnified view of a few heartbeats. It looks pretty good! Here’s the code I used to do all the calculations:

 import wave, struct, numpy, pylab, scipy

 fname='./success3.wav'

 def readwave(wavfilename):
     """load raw data directly from a WAV file."""
     global rate
     w=wave.open(wavfilename,'rb')
     (nchannel, width, rate, length, comptype, compname) = w.getparams()
     print "[%s] %d HZ (%0.2fsec)" %(wavfilename, rate, length/float(rate))
     frames = w.readframes(length)
     return numpy.array(struct.unpack("%sh" %length*nchannel,frames))

 def shrink(data,deg=100):
     """condense a linear data array by a multiple of [deg]."""
     global rate
     small=[]
     print "starting with", len(data)
     for i in range(len(data)/deg):
         small.append(numpy.average(data[i*deg:(i+1)*deg]))
     print "ending with", len(small)
     rate = rate/deg
     #return small[40000:50000]
     return small

 def normalize(data):
     """make all data fit between -.5 and +.5"""
     data=data-numpy.average(data)
     big=float(max(data))
     sml=float(min(data))
     data=data/abs(big-sml)
     data=data+float(abs(min(data)))-.47
     return data

 def smooth(data,deg=20,expand=False):
     """moving window average (deg = window size)."""
     for i in range(len(data)-deg):
         if i==0: cur,smooth=sum(data[0:deg]),[]
         smooth.append(cur/deg)
         cur=cur-data[i]+data[i+deg]
     if expand:
         for i in range(deg):
             smooth.append(smooth[-1])
     return smooth

 def smoothListGaussian(list,degree=10,expand=False):
     window=degree*2-1
     weight=numpy.array([1.0]*window)
     weightGauss=[]
     for i in range(window):
         i=i-degree+1
         frac=i/float(window)
         gauss=1/(numpy.exp((4*(frac))**2))
         weightGauss.append(gauss)
     weight=numpy.array(weightGauss)*weight
     smoothed=[0.0]*(len(list)-window)
     for i in range(len(smoothed)):
         smoothed[i]=sum(numpy.array(list[i:i+window])*weight)/sum(weight)
     if expand:
         for i in range((degree*2)-1):
             smoothed.append(smoothed[-1])
     return smoothed

 def goodSmooth(data):
     #data=smooth(fix,20,True)
     data=smooth(fix,100,True)
     #data=smooth(fix,20,True)
     return data

 def makeabs(data):
     """center linear data to its average value."""
     for i in range(len(data)): data[i]=abs(data[i])
     return data

 def invert(data):
     """obviously."""
     for i in range(len(data)): data[i]=-data[i]
     return data

 def loadwav(fname):
     """a do-everything function to get usable, smoothed data from a WAV."""
     wav=readwave(fname)
     wav=shrink(wav)
     wav=invert(wav)
     wav=smooth(wav)
     wav=smooth(wav,10)
     wav=normalize(wav)
     Xs=getXs(wav)
     return Xs,wav

 def getXs(datalen):
     """calculate time positions based on WAV frequency resolution."""
     Xs=[]
     for i in range(len(datalen)):
         Xs.append(i*(1/float(rate)))
     print len(datalen), len(Xs)
     return Xs

 def integrate(data):
     """integrate the function with respect to its order."""
     inte=[]
     for i in range(len(data)-1):
         inte.append(abs(data[i]-data[i+1]))
     inte.append(inte[-1])
     return inte

 def getPoints(Xs,data,res=10):
     """return X,Y coordinates of R peaks and calculate R-R based heartrate."""
     pXs,pYs,pHRs=[],[],[]
     for i in range(res,len(data)-res):
         if data[i]>data[i-res]+.1 and data[i]>data[i+res]+.1:
             if data[i]>data[i-1] and data[i]>data[i+1]:
                 pXs.append(Xs[i])
                 pYs.append(data[i])
                 if len(pXs)>1:
                     pHRs.append((1.0/(pXs[-1]-pXs[-2]))*60.0)
     pHRs.append(pHRs[-1])
     return pXs,pYs,pHRs

 def bandStop(fft,fftx,low,high,show=True):
     lbl="%d-%d"%(low,high)
     print "band-stopping:",lbl
     if show:
         col=pylab.cm.spectral(low/1200.)
         pylab.axvspan(low,high,alpha=.4,ec='none',label=lbl,fc=col)
         #pylab.axvspan(-low,-high,fc='r',alpha=.3)
     for i in range(len(fft)):
         if abs(fftx[i])>low and abs(fftx[i])<high :
             fft[i]=0
     return fft

 def getXs(data):
     xs=numpy.array(range(len(data)))
     xs=xs*(1.0/rate)
     return xs

 def clip(x,deg=1000):
     return numpy.array(x[deg:-deg])

 pylab.figure(figsize=(12,8))
 raw = invert(shrink(readwave(fname),10))
 xs = getXs(raw)
 fftr = numpy.fft.fft(raw)
 fft = fftr[:]
 fftx= numpy.fft.fftfreq(len(raw), d=(1.0/(rate)))

 pylab.subplot(2,1,1)
 pylab.plot(fftx,abs(fftr),'k')

 fft=bandStop(fft,fftx,30,123)
 fft=bandStop(fft,fftx,160,184)
 fft=bandStop(fft,fftx,294,303)
 fft=bandStop(fft,fftx,386,423)
 fft=bandStop(fft,fftx,534,539)
 fft=bandStop(fft,fftx,585,610)
 fft=bandStop(fft,fftx,654,660)
 fft=bandStop(fft,fftx,773,778)
 fft=bandStop(fft,fftx,893,900)
 fft=bandStop(fft,fftx,1100,max(fftx))
 pylab.axis([0,1200,0,2*10**6])
 pylab.legend()
 pylab.title("Power Spectral Analysis",fontsize=28)
 pylab.ylabel("Power",fontsize=20)
 pylab.xlabel("Frequency (Hz)",fontsize=20)

 pylab.subplot(2,1,2)
 pylab.title("Original Trace",fontsize=28)
 pylab.ylabel("Potential",fontsize=20)
 pylab.xlabel("Time (sec)",fontsize=20)
 pylab.plot(clip(xs),clip(raw),color='.8',label='1: raw')

 fix = scipy.ifft(fft)
 pylab.plot(clip(xs),clip(fix)+5000,color='.6',label='2: band-stop')
 pylab.plot(clip(xs),clip(goodSmooth(fix))-5000,'k',label='3: smoothed')
 pylab.legend()
 pylab.title("Band-Stop Filtered Trace",fontsize=28)
 pylab.ylabel("Potential",fontsize=20)
 pylab.xlabel("Time (sec)",fontsize=20)

 pylab.subplots_adjust(hspace=.5)
 pylab.savefig('out.png',dpi=100)
 pylab.show()
 print "COMPLETE"




Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

I’ve succeeded in building my own electrocardiograph (ECG) to record the electrical activity of my own heart! Briefly, I built a micropotential amplifier using an op-amp and attached it to makeshift electrodes on my chest (pennies and shampoo), fed the amplified signal into my sound card, and recorded it as a WAV. The signal is very noisy though. I was able to do a great job at removing this noise using band/frequency filters in GoldWave (audio editing software designed to handle WAV files). I band-blocked 50-70 Hz (which removed the oscillations from the 60 Hz AC lines running around my apartment). I then wrote the Python code (at the bottom of this entry) to load this WAV file as a single list of numbers (voltage potentials). I performed a data condensation algorithm (converting 100 points of raw WAV data into a single, averaged point, lessening my processing load by 100x), followed by two consecutive moving window averages (20-point window, performed on the condensed data). The result was a voltage reading that had most of the noise removed and a beautiful ECG signal emerged! I also tossed in some code to determine the peak of the R wave, label it (yellow dot), and use the inverse R-R time distance to calculate heart rate.

This is my actual ECC signal as record by a circuit similar to the one in the previous entry, recorded through my sound card, and processed with the Python script below. You can start to see the Q, R, S, and T components. I can’t wait to solder-up a prototype (it’s currently breadboarded) and try to analyze hours of data rather than just a few seconds. I’ll take pictures of this device soon.

And here’s the code I used: note that it relies on the WAV file I recorded. This code has extra functions not required to produce the image above, but I left them in in case they may be useful.

 import wave, struct, numpy, pylab, scipy

 def readwave(wavfilename):
     """load raw data directly from a WAV file."""
     global rate
     w=wave.open(wavfilename,'rb')
     (nchannel, width, rate, length, comptype, compname) = w.getparams()
     print "[%s] %d HZ (%0.2fsec)" %(wavfilename, rate, length/float(rate))
     frames = w.readframes(length)
     return numpy.array(struct.unpack("%sh" %length*nchannel,frames))

 def shrink(data,deg=100):
     """condense a linear data array by a multiple of [deg]."""
     global rate
     small=[]
     print "starting with", len(data)
     for i in range(len(data)/deg):
         small.append(numpy.average(data[i*deg:(i+1)*deg]))
     print "ending with", len(small)
     rate = rate/deg
     return small

 def normalize(data):
     """make all data fit between -.5 and +.5"""
     data=data-numpy.average(data)
     big=float(max(data))
     sml=float(min(data))
     data=data/abs(big-sml)
     data=data+float(abs(min(data)))-.47
     return data

 def smooth(data,deg=20):
     """moving window average (deg = window size)."""
     for i in range(len(data)-deg):
         if i==0: cur,smooth=sum(data[0:deg]),[]
         smooth.append(cur/deg)
         cur=cur-data[i]+data[i+deg]
     return smooth

 def makeabs(data):
     """center linear data to its average value."""
     for i in range(len(data)): data[i]=abs(data[i])
     return data

 def invert(data):
     """obviously."""
     for i in range(len(data)): data[i]=-data[i]
     return data

 def loadwav(fname='./wavs/bandpassed.wav'):
     """a do-everything function to get usable, smoothed data from a WAV."""
     wav=readwave(fname)
     wav=shrink(wav)
     wav=invert(wav)
     wav=smooth(wav)
     wav=smooth(wav,10)
     wav=normalize(wav)
     Xs=getXs(wav)
     return Xs,wav

 def getXs(datalen):
     """calculate time positions based on WAV frequency resolution."""
     Xs=[]
     for i in range(len(datalen)):
         Xs.append(i*(1/float(rate)))
     print len(datalen), len(Xs)
     return Xs

 def integrate(data):
     """integrate the function with respect to its order."""
     inte=[]
     for i in range(len(data)-1):
         inte.append(abs(data[i]-data[i+1]))
     inte.append(inte[-1])
     return inte

 def getPoints(Xs,data,res=10):
     """return X,Y coordinates of R peaks and calculate R-R based heartrate."""
     pXs,pYs,pHRs=[],[],[]
     for i in range(res,len(data)-res):
         if data[i]>data[i-res]+.1 and data[i]>data[i+res]+.1:
             if data[i]>data[i-1] and data[i]>data[i+1]:
                 pXs.append(Xs[i])
                 pYs.append(data[i])
                 if len(pXs)>1:
                     pHRs.append((1.0/(pXs[-1]-pXs[-2]))*60.0)
     pHRs.append(pHRs[-1])
     return pXs,pYs,pHRs

 Xs,Ys=loadwav()
 px,py,pHR=getPoints(Xs,Ys)

 pylab.figure(figsize=(12,6))
 pylab.subplot(2,1,1)
 #pylab.axhline(color='.4',linestyle=':')
 pylab.plot(Xs,Ys,'b-')
 pylab.plot(px,py,'y.')
 pylab.axis([None,None,-.6,.6])
 pylab.title("DIY Electrocardiogram - Trial 1",fontsize=26)
 pylab.ylabel("Normalized Potential",fontsize=16)
 #pylab.xlabel("Time (sec)")
 ax=pylab.axis()
 pylab.subplot(2,1,2)
 pylab.plot(px,pHR,'k:')
 pylab.plot(px,pHR,'b.')
 pylab.axis([ax[0],ax[1],None,None])
 pylab.ylabel("Heart Rate (BPM)",fontsize=16)
 pylab.xlabel("Time (seconds)",fontsize=16)
 pylab.savefig("test.png",dpi=120)
 pylab.show()
 print "DONE"




Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

I kept working on my DIY ECG machine (I had to change the values of some of the resisters) and it looks like I’m getting some valid signals! By recording the potential using my sound card (the microphone port seems to be a nice analog to digital converter that every PC has) I was able record my ECG with sound recording software, smooth it, and this is what it looks like.

This was based on a circuit I made using a single op-amp (A LM324 from RadioShack $1.49). The op-amp amplifies micro-potential generated by my heart and outputs it in a way that I can connect it to a microphone jack. The signal is very noisy though. I’m thinking about making the more advanced circuit (with 6 op-amps) to aim for a better signal-to-noise ratio, but first I’ll try coding my way out of the noise…





Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

I followed-through on yesterday’s post and actually tried to build an ECG machine. I had a very small amount of time to work on it, so instead of building the fancy circuit (with 6 band-pass filtered op-amps and diodes posted in the previous entry) I built the most crude circuit that would theoretically work.

I used just one of the 4 available op-amps from a LM324. I built this, hooked it up to my sound card, and made electrodes by soldering wires to pennies. After a good lick, I attached the pennies to my chest with tape and tried recording. Every time the pennies made contact with my skin, I would see noise on the trace, but I couldn’t seem to isolate a strong heartbeat signal. This is what I saw and the circuit I build to see it:

Perhaps this project will be working soon. Many techno-savvy people have made these DIY ECG machines, but not many describe how to interpret the data. Since I’m planning on building it, testing it, recording ECG data, and processing/analyzing it, I’ll may have something unique on the internet.





Update: The DIY ECG project has had several iterations. The latest one can be viewed here: https://www.swharden.com/wp/2019-03-15-sound-card-ecg-with-ad8232/

Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Last night my wife put her head on my chest while we were watching a movie. A minute or two later I felt a light sinking feeling in my upper chest, and my wife looked up at me in horror. “Your heart stopped beating!” I assured her that everything was okay (it quickly resumed), and that it happens all the time. I feel the sinking feeling often, know it’s because my heart is briefly beating irregularly, and assume it’s normal. After all, your heart isn’t a robot, it’s a living organ doing the best it can. It’s never perfectly regular, and presumably everybody has momentary irregularities, they just don’t notice them. When I got in bed I began wondering how regular irregular heartbeats are. What would the chances be that I have some kind of arrhythmia? I’ve had a checkup not too long ago by a family practice physician who used a stethoscope on my back to listen to my heartbeat, and he didn’t notice anything. Then again, how often does a quick listen with a stethoscope detect subtle or occasional arrhythmias?

I know that whatever problem I have is likely too small to cause any serious troubles, but at the same time I’m becoming obsessed as to determining exactly what my problem is. How many times a day does my heart skip beats? What about nighttime? If only there were some way to record heartbeat data, then I could analyze it and determine the severity of my problem. But wait, data? That would be hours of heartbeat recordings… that means… YES! An idea for a DIY hardware that produces large amounts of data requiring the writing of data analysis software!

Naturally, my thoughts began to overwhelm my reality as soon as Python entered the scene. I wondered how I could use my PC to record my heartbeat, without spending much money on hardware, and only using software I write myself. I pondered this on the way to work this morning, and came up with two possible methods:

Method 1: acoustic recordings. This would be the easiest way to record my heartbeat. I could tape a stethoscope to my chest, insert a small microphone in the earpiece, connect the microphone to my PC, and record sound data for several hours. Theoretically it would work, but it would be highly prone to noise from breathing, and I would have to lay perfectly still to avoid noise caused by movements. The data (trace) would have to be smoothed, processed with a band-pass filter (to eliminate interference), and heartbeats could be calculated. However, this would only give me heart beat time information…

Method 2: electrical recordings. This would be a little more complicated, but generate much more information. I could record the electrical activity of my heart, and the charts would look like the cool electrocardiograms (ECGs) that you see on TV shows. I did a little Googling and found that similar things have been done before with common electrical components. I think I’m going to follow the guide on this page and build the circuit seen below:

Supposedly, the data I can obtain looks something like the image below. I’d attach 3 electrodes to my body (chest, arm, and leg), hook them up to my little circuit, then connect to circuit to my PCs sound card. I’d record the trace (maybe while I sleep?) and analyze it with Python/Numpy/Matplotlib. There are several websites which demonstrate how to build DIY ECG recording devices, but none of these seem to go into depth analyzing the data they obtain. Hopefully I could fill this little niche on the internet. We’ll see what happens. I have my thesis to work on, and a whole bunch of other stuff on my plate right now.

UPDATE: I found an much simpler ECG circuit I can make from parts I already have at my house. It has tons of noise, but maybe I can filter that out somehow?