The personal website of Scott W Harden
January 13th, 2009

DIY ECG?

⚠️ Check out my newer ECG designs:

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?

Markdown source code last modified on January 18th, 2021
---
title: DIY ECG?
date: 2009-01-13 11:19:27
tags: diyECG
---

# DIY ECG?

> **⚠️ Check out my newer ECG designs:** 
* [**Sound Card ECG with AD8232**](https://swharden.com/blog/2019-03-15-sound-card-ecg-with-ad8232/)
* [**Single op-amp ECG**](https://swharden.com/blog/2016-08-08-diy-ecg-with-1-op-amp/)

__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](http://www-users.med.cornell.edu/~dchristi/qecg/localecg.html) and build the circuit seen below:

<div class="text-center img-border img-medium">

![](bigsch.gif)

</div>

__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.

<div class="text-center img-border">

[![](diy_ecg_thumb.jpg)](diy_ecg.jpg)

</div>

__UPDATE:__ I found an [much simpler ECG circuit](http://www.univie.ac.at/cga/courses/BE513/EKG/lab.html) I can make from parts I already have at my house. It has tons of noise, but maybe I can filter that out somehow?

November 27th, 2008

Fixing Slow Internet in Ubuntu

I recently swapped my two main PCs in my house. The "headless" (no monitor) media PC (whose job consists of downloading, storing, and playing movies) connected directly to my TV, and our standard desktop PC which my wife uses most of the time. I decided to do the swap because the media PC was way nicer than our desktop PC, and since the media PC is just playing movies and downloading torrents, I figured the extra processing power / ram / video acceleration could be put to better use. Anyhow, I decided (in both cases) to completely start fresh by wiping hard drives clean and reinstalling Ubuntu linux (I'm using 8.10 currently). However, after the installation I noticed a peculiar problem. I'll quote it to emphasize it...

Browsing the internet was very slow. When I'd click a link on a website, it would take several seconds before it seemed to even try to go to the next page. The same thing would happen if I manually typed-in a new website. I tried disabling IPv6 in firefox's about:config and in the /etc/init.d/aliases file, but it didn't help!

The solution for me was simple, and since I spent a lot of time searching forums I know I'm not the only one with this problem. Disabling IPv6 was suggested in 99% of similar posts. My solution took a while to uncover, so I figured I'd write it here. The basic problem is that my DHCP (auto-configured IP address) settings were screwed up, and my manually setting them I fixed the problem. Here's what I did...

Start by right-clicking your network icon (wireless in my case) and selecting connection information

Check out your current configuration. Is a local address (192.168.*.*) set for the primary DNS server? If so, that's your problem! Note your secondary server. We'll set it as your primary...

Continue by right-clicking your network icon (wireless in my case) and selecting edit connections*. Open the tab corresponding to your internet connection (wired or wireless - wireless in my case), select your connection, and click __Edit__

Use this screen to manually enter the information from the information screen you saw earlier, but making sure not to list any local IP addresses as the DNS servers. Save your settings, close the windows, and the problem should be immediately corrected. Leave "search domains" blank, that's important too. Good luck!!!

Markdown source code last modified on January 18th, 2021
---
title: Fixing Slow Internet in Ubuntu
date: 2008-11-27 00:22:18
---

# Fixing Slow Internet in Ubuntu

 __I recently swapped my two main PCs in my house.__  The "headless" (no monitor) media PC (whose job consists of downloading, storing, and playing movies) connected directly to my TV, and our standard desktop PC which my wife uses most of the time.  I decided to do the swap because the media PC was way nicer than our desktop PC, and since the media PC is just playing movies and downloading torrents, I figured the extra processing power / ram / video acceleration could be put to better use.  Anyhow, I decided (in both cases) to completely start fresh by wiping hard drives clean and reinstalling Ubuntu linux (I'm using 8.10 currently).  However, after the installation I noticed a peculiar problem.  I'll quote it to emphasize it...

>  Browsing the internet was very slow. When I'd click a link on a website, it would take several seconds before it seemed to even try to go to the next page. The same thing would happen if I manually typed-in a new website. I tried disabling IPv6 in firefox's about:config and in the /etc/init.d/aliases file, but it didn't help!

__The solution for me was simple, and since__ I spent a lot of time searching forums I know I'm not the only one with this problem.  Disabling IPv6 was suggested in 99% of similar posts.  My solution took a while to uncover, so I figured I'd write it here.  The basic problem is that my DHCP (auto-configured IP address) settings were screwed up, and my manually setting them I fixed the problem.  Here's what I did...

<div class="text-center img-border">

[![](dnsfix1_thumb.jpg)](dnsfix1.png)

</div>


 Start by right-clicking your network icon (wireless in my case) and selecting __connection information__

<div class="text-center img-border">

[![](dnsfix4_thumb.jpg)](dnsfix4.png)

</div>

Check out your current configuration.  __Is a local address (192.168.\*.\*) set for the primary DNS server?__  If so, that's your problem!  Note your secondary server.  We'll set it as your primary...

<div class="text-center img-border">

[![](dnsfix1_thumb.jpg)](dnsfix1.png)

</div>

Continue by right-clicking your network icon (wireless in my case) and selecting __edit connections\*. Open the tab corresponding to your internet connection (wired or wireless - wireless in my case), select your connection, and click ____Edit__

<div class="text-center img-border">

[![](dnsfix3_thumb.jpg)](dnsfix3.png)

</div>

Use this screen to __manually enter the information from the information screen you saw earlier, but making sure not to list any local IP addresses as the DNS servers.__  Save your settings, close the windows, and the problem should be immediately corrected.  Leave "search domains" blank, that's important too. Good luck!!!
November 24th, 2008

Compress Strings and Store to Files in Python

While writing code for my graduate research thesis I came across the need to lightly compress a huge and complex variable (a massive 3D data array) and store it in a text file for later retrieval. I decided to use the zlib compression library because it's open source and works pretty much on every platform. I ran into a snag for a while though, because whenever I loaded data from a text file it wouldn't properly decompress. I fixed this problem by adding the "rb" to the open line, forcing python to read the text file as binary data rather than ascii data. Below is my code, written in two functions to save/load compressed string data to/from files in Python.

import zlib  

def saveIt(data,fname):  
    data=str(data)  
    data=zlib.compress(data)  
    f=open(fname,'wb')  
    f.write(data)  
    f.close()  
    return  

def openIt(fname,evaluate=True):  
    f=open(fname,'rb')  
    data=f.read()  
    f.close()  
    data=zlib.decompress(data)  
    if evaluate: data=eval(data)  
    return data  

Oh yeah, don't forget the evaluate option in the openIt function. If set to True (default), the returned variable will be an evaluated object. For example, [[1,2],[3,4]] will be returned as an actual 2D list, not just a string. How convenient is that?

Markdown source code last modified on January 18th, 2021
---
title: Compress and Store Files in Python
date: 2008-11-24 17:48:16
tags: python, old
---

# Compress Strings and Store to Files in Python

 __While writing code for my graduate research thesis__ I came across the need to lightly compress a huge and complex variable (a massive 3D data array) and store it in a text file for later retrieval.  I decided to use the [zlib](http://en.wikipedia.org/wiki/Zlib) compression library because it's open source and works pretty much on every platform.  I ran into a snag for a while though, because whenever I loaded data from a text file it wouldn't properly decompress.  I fixed this problem by adding the "rb" to the open line, forcing python to read the text file as binary data rather than ascii data.  Below is my code, written in two functions to save/load compressed string data to/from files in Python.

```python
import zlib  
  
def saveIt(data,fname):  
    data=str(data)  
    data=zlib.compress(data)  
    f=open(fname,'wb')  
    f.write(data)  
    f.close()  
    return  
  
def openIt(fname,evaluate=True):  
    f=open(fname,'rb')  
    data=f.read()  
    f.close()  
    data=zlib.decompress(data)  
    if evaluate: data=eval(data)  
    return data  
```

__Oh yeah, don't forget__ the evaluate option in the openIt function.  If set to True (default), the returned variable will be an evaluated object.  For example, `[[1,2],[3,4]]` will be returned as an actual 2D list, not just a string.  How convenient is that?
November 22nd, 2008

Run Ubuntu Live CD From a USB Drive

I accidentally nuked my laptop's 80G hard drive this morning (D'OH!) while shuffling around partitions. Supposedly there's a valid windows (XP) installation on there still that's about 20G. I'd love to repair it so I can use it today while I'm in the confocal room, but I don't have an Ubuntu CD, Windows CD, or any CD for that matter! I looked around, but I guess blank CD-Rs aren't something that's standard in molecular biology laboratories. Anyhow, I wanted to install the new Ubuntu 8.10 Linux distribution, and I've downloaded the ISO, but since I can't find a CD to burn it to I decided to try booting from a USB drive (something I've never done before). I found an AWESOME program which specialized in putting ISO files onto bootable USB drives. It's called UNetBootin and it's free (of course), runs on Linux or Windows, and has some built-in options for various linux distributions. I can repair my PC now! Yay!

Markdown source code last modified on January 18th, 2021
---
title: Run Ubuntu Live CD From a USB Drive
date: 2008-11-22 15:36:16
---

# Run Ubuntu Live CD From a USB Drive

 __I accidentally nuked my laptop's 80G hard drive this morning__ (D'OH!) while shuffling around partitions.  Supposedly there's a valid windows (XP) installation on there still that's about 20G.  I'd love to repair it so I can use it today while I'm in the confocal room, but I don't have an Ubuntu CD, Windows CD, or any CD for that matter!  I looked around, but I guess blank CD-Rs aren't something that's standard in molecular biology laboratories.  Anyhow, I wanted to install the new Ubuntu 8.10 Linux distribution, and I've downloaded the ISO, but since I can't find a CD to burn it to I decided to try booting from a USB drive (something I've never done before).  I found an _AWESOME_ program which specialized in putting ISO files onto bootable USB drives.  It's called [UNetBootin](http://unetbootin.sourceforge.net/) and it's free (of course), runs on Linux or Windows,  and has some built-in options for various linux distributions.  I can repair my PC now!  Yay!

<div class="text-center img-border">

![](unetbootin.jpg)

</div>
November 17th, 2008

Linear Data Smoothing in Python

⚠️ SEE UPDATED POST: Signal Filtering in Python

def smoothListGaussian(list, degree=5):
    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)
    return smoothed

Provide a list and it will return a smoother version of the data. The Gaussian smoothing function I wrote is leagues better than a moving window average method, for reasons that are obvious when viewing the chart below. Surprisingly, the moving triangle method appears to be very similar to the Gaussian function at low degrees of spread. However, for large numbers of data points, the Gaussian function should perform better.

import pylab
import numpy

def smoothList(list, strippedXs=False, degree=10):
    if strippedXs == True:
        return Xs[0:-(len(list)-(len(list)-degree+1))]
    smoothed = [0]*(len(list)-degree+1)
    for i in range(len(smoothed)):
        smoothed[i] = sum(list[i:i+degree])/float(degree)
    return smoothed

def smoothListTriangle(list, strippedXs=False, degree=5):
    weight = []
    window = degree*2-1
    smoothed = [0.0]*(len(list)-window)
    for x in range(1, 2*degree):
        weight.append(degree-abs(degree-x))
    w = numpy.array(weight)
    for i in range(len(smoothed)):
        smoothed[i] = sum(numpy.array(list[i:i+window])*w)/float(sum(w))
    return smoothed

def smoothListGaussian(list, strippedXs=False, degree=5):
    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)
    return smoothed

### DUMMY DATA ###
data = [0]*30  # 30 "0"s in a row
data[15] = 1  # the middle one is "1"

### PLOT DIFFERENT SMOOTHING FUNCTIONS ###
pylab.figure(figsize=(550/80, 700/80))
pylab.suptitle('1D Data Smoothing', fontsize=16)
pylab.subplot(4, 1, 1)
p1 = pylab.plot(data, ".k")
p1 = pylab.plot(data, "-k")
a = pylab.axis()
pylab.axis([a[0], a[1], -.1, 1.1])
pylab.text(2, .8, "raw data", fontsize=14)
pylab.subplot(4, 1, 2)
p1 = pylab.plot(smoothList(data), ".k")
p1 = pylab.plot(smoothList(data), "-k")
a = pylab.axis()
pylab.axis([a[0], a[1], -.1, .4])
pylab.text(2, .3, "moving window average", fontsize=14)
pylab.subplot(4, 1, 3)
p1 = pylab.plot(smoothListTriangle(data), ".k")
p1 = pylab.plot(smoothListTriangle(data), "-k")
pylab.axis([a[0], a[1], -.1, .4])
pylab.text(2, .3, "moving triangle", fontsize=14)
pylab.subplot(4, 1, 4)
p1 = pylab.plot(smoothListGaussian(data), ".k")
p1 = pylab.plot(smoothListGaussian(data), "-k")
pylab.axis([a[0], a[1], -.1, .4])
pylab.text(2, .3, "moving gaussian", fontsize=14)
# pylab.show()
pylab.savefig("smooth.png", dpi=80)

This data needs smoothing. Below is a visual representation of the differences in the methods of smoothing.

The degree of window coverage for the moving window average, moving triangle, and Gaussian functions are 10, 5, and 5 respectively. Also note that (due to the handling of the "degree" variable between the different functions) the actual number of data points assessed in these three functions are 10, 9, and 9 respectively. The degree for the last two functions represents "spread" from each point, whereas the first one represents the total number of points to be averaged for the moving average.

Markdown source code last modified on January 18th, 2021
---
title: Linear Data Smoothing in Python
date: 2008-11-17 18:50:10
tags: old, python
---

# Linear Data Smoothing in Python

> **⚠️ SEE UPDATED POST:** [**Signal Filtering in Python**](https://swharden.com/blog/2020-09-23-signal-filtering-in-python/)

```python
def smoothListGaussian(list, degree=5):
    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)
    return smoothed
```

Provide a list and it will return a smoother version of the data. The Gaussian smoothing function I wrote is leagues better than a moving window average method, for reasons that are obvious when viewing the chart below. Surprisingly, the moving triangle method appears to be very similar to the Gaussian function at low degrees of spread. However, for large numbers of data points, the Gaussian function should perform better.

<div class="text-center">

[![](smooth_thumb.jpg)](smooth.png)

</div>

```python
import pylab
import numpy

def smoothList(list, strippedXs=False, degree=10):
    if strippedXs == True:
        return Xs[0:-(len(list)-(len(list)-degree+1))]
    smoothed = [0]*(len(list)-degree+1)
    for i in range(len(smoothed)):
        smoothed[i] = sum(list[i:i+degree])/float(degree)
    return smoothed

def smoothListTriangle(list, strippedXs=False, degree=5):
    weight = []
    window = degree*2-1
    smoothed = [0.0]*(len(list)-window)
    for x in range(1, 2*degree):
        weight.append(degree-abs(degree-x))
    w = numpy.array(weight)
    for i in range(len(smoothed)):
        smoothed[i] = sum(numpy.array(list[i:i+window])*w)/float(sum(w))
    return smoothed

def smoothListGaussian(list, strippedXs=False, degree=5):
    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)
    return smoothed

### DUMMY DATA ###
data = [0]*30  # 30 "0"s in a row
data[15] = 1  # the middle one is "1"

### PLOT DIFFERENT SMOOTHING FUNCTIONS ###
pylab.figure(figsize=(550/80, 700/80))
pylab.suptitle('1D Data Smoothing', fontsize=16)
pylab.subplot(4, 1, 1)
p1 = pylab.plot(data, ".k")
p1 = pylab.plot(data, "-k")
a = pylab.axis()
pylab.axis([a[0], a[1], -.1, 1.1])
pylab.text(2, .8, "raw data", fontsize=14)
pylab.subplot(4, 1, 2)
p1 = pylab.plot(smoothList(data), ".k")
p1 = pylab.plot(smoothList(data), "-k")
a = pylab.axis()
pylab.axis([a[0], a[1], -.1, .4])
pylab.text(2, .3, "moving window average", fontsize=14)
pylab.subplot(4, 1, 3)
p1 = pylab.plot(smoothListTriangle(data), ".k")
p1 = pylab.plot(smoothListTriangle(data), "-k")
pylab.axis([a[0], a[1], -.1, .4])
pylab.text(2, .3, "moving triangle", fontsize=14)
pylab.subplot(4, 1, 4)
p1 = pylab.plot(smoothListGaussian(data), ".k")
p1 = pylab.plot(smoothListGaussian(data), "-k")
pylab.axis([a[0], a[1], -.1, .4])
pylab.text(2, .3, "moving gaussian", fontsize=14)
# pylab.show()
pylab.savefig("smooth.png", dpi=80)
```

This data needs smoothing. Below is a visual representation of the differences in the methods of smoothing.

<div class="text-center">

[![](smooth2_thumb.jpg)](smooth2.png)

</div>

The degree of window coverage for the moving window average, moving triangle, and Gaussian functions are 10, 5, and 5 respectively. Also note that (due to the handling of the "degree" variable between the different functions) the actual number of data points assessed in these three functions are 10, 9, and 9 respectively. The degree for the last two functions represents "spread" from each point, whereas the first one represents the total number of points to be averaged for the moving average.
Pages