Electrocardiogram (ECG)

This was a project at the end of my Circuits and Signals class. The electrocardiogram (ECG) is a classic example of a lifesaving application of electrical engineering. The heart is controlled by the nervous system, which contains a chain of electrochemical impulses. The following graphic shows the electrical potential of a nerve as it transmits a signal.

Components of a nerve signal

Electrodes placed on the body across the heart can collect the nerve signals that direct the heart to pump. Analyzing these signals can have lifesaving implications, like detecting arrhythmias.

Proper placement of ECG electrodes

Trying to read the signals directly from these electrodes is impractical. The signals are too small and too noisy to get anything of use. Common ECG signals have a p-p amplitude of 100 mV and have compnents from 0.1 Hz to 400 Hz. This ECG takes multiple steps to collect a useful signal:

  1. AD627 amplifier to obtain a large enough signal
  2. High pass filter to eliminate the DC component of the signal
  3. Low pass filter to eliminate noise
  4. Analog to digital converter (ADC) to record the signal
  5. Digital signal processing in MATLAB to obtain a clean, usable ECG trace

ECG circuit block diagram

ECG circuit schematic

Amplification

Again, the raw ECG signal is unusable. The AD627 instrumentation amplifier takes the raw signal and amplifies it so it can be filtered, recorded, and analyzed.

AD627 instrumentation amplifier

The supply power was chosen at 1.5 V, allowing for the use of a AAA battery for power, isolating the patient from the electrical grid. To achieve a desired gain of 25, RG was set to 10k. Testing the circuit, the real gain was 24.6. The cutoff frequency was 12.5 kHz, which is ok, as the highest desired signal is 400 Hz. Finally, the leads from the electrodes were arranged in a twisted pair to reduce noise pickup from the line. The amplified, unfiltered trace was recorded and is shown below.

Unfiltered ECG trace

The spikes in potential with each heart rate are clear but the rest of the signal is useless in its current state.

Filtering

The ECG reading has an unwanted DC component from the potential of the human body. An active high-pass filter using an op-amp was used to eliminate it. A cutoff frequency of 0.265 Hz eliminates this DC component without sacrificing too many low-frequency components. The maximum gain of this amplifier is about -0.8.

High-pass filter

To eliminate unwanted high-frequency components (noise), a low-pass filter with a cutoff frequency of 226 Hz was used. The gain for this stage was selected at 150; this allowed for the final signal to fill the +/- 1.5 V range available for A/D conversion.

Low-pass filter

Recording

The final, constructed circuit and the recorded trace are shown below.

ECG circuit

ECG trace from ADALM2000 software

Post-Processing

A MATLAB program was used to further process the signal. First, a Parks-McClellan filter with the same cutoff frequencies as the analog filters was used to clean up the trace. Second, a notch filter was used to eliminate 60Hz noise from the power grid of the same frequency.

ECG trace processed in MATLAB

The final trace is clear and usable. The heart rate is around 75 bpm, which is normal for a college student on caffeine.

clear;
clf;
%%load values from csv
T=readtable('ecg.csv');
time = T.time;
v=T.V2;

%%plot original ecg curve
subplot(4, 1, 1)
plot(time, v)
xlabel('Time (s)')
ylabel('Potential (V)')
title('Original ECG trace')

%%filter high and low frequencies and plot
rp = 3;           % Passband ripple in dB
rs = 40;          % Stopband ripple in dB
fs = 1000;        % Sampling frequency
f = [0.26 226];    % Cutoff frequencies
a = [1 0];        % Desired amplitudes
dev = [(10^(rp/20)-1)/(10^(rp/20)+1) 10^(-rs/20)];
[n,fo,ao,w] = firpmord(f,a,dev,fs);
b = firpm(n,fo,ao,w);
vfilt=filter(b,1,v);

subplot(4, 1, 2)
plot(time, vfilt)
xlabel('Time (s)')
ylabel('Potential (V)')
title('Filtered ECG trace, Pt1')

%%notch 60hz
%below 60
rp = 3;           % Passband ripple in dB
rs = 500;          % Stopband ripple in dB
fs = 1000;        % Sampling frequency
f = [0 59];    % Cutoff frequencies
a = [1 0];        % Desired amplitudes
dev = [(10^(rp/20)-1)/(10^(rp/20)+1) 10^(-rs/20)];
[n,fo,ao,w] = firpmord(f,a,dev,fs);
b = firpm(n,fo,ao,w);
vfiltbelow60=filter(b,1,v);

rp = 3;           % Passband ripple in dB
rs = 500;          % Stopband ripple in dB
fs = 1000;        % Sampling frequency
f = [61 500];    % Cutoff frequencies
a = [1 0];        % Desired amplitudes
dev = [(10^(rp/20)-1)/(10^(rp/20)+1) 10^(-rs/20)];
[n,fo,ao,w] = firpmord(f,a,dev,fs);
b = firpm(n,fo,ao,w);
vfiltabove60=filter(b,1,v);

vfilt=vfiltbelow60+vfiltabove60;
rp = 3;           % Passband ripple in dB
rs = 40;          % Stopband ripple in dB
fs = 1000;        % Sampling frequency
f = [0.26 226];    % Cutoff frequencies
a = [1 0];        % Desired amplitudes
dev = [(10^(rp/20)-1)/(10^(rp/20)+1) 10^(-rs/20)];
[n,fo,ao,w] = firpmord(f,a,dev,fs);
b = firpm(n,fo,ao,w);
vfilt2=filter(b,1,vfilt);

subplot(4, 1, 3)
plot(time, vfilt2)
xlabel('Time (s)')
ylabel('Potential (V)')
title('Filtered ECG trace, Pt2')

%%calculate hr
beats=findpeaks(v,fs,'MinPeakProminence',1); %beats (prominence of 1 V)
time=(size(v)/fs);
time=time(1);
samplespermin=60/time;
bpm=size(beats)*samplespermin;
bpm=bpm(1);
subplot(4, 1, 4);
textout=strcat("BPM: ", num2str(bpm));
text(0.5,0.5,textout); axis off

The full development process is detailed in the reports below.

Amplification; mobile users click here

Analog filtering; mobile users click here

Digital filtering; mobile users click here