Zoom Icon

Introduction to ECG filtering

From UIC

A brief introduction about ecg filtering

Contents


Infos
Author: epokh
Email: matrix.epokh@gmail.com
Website: www.epokh.org/drupy
Date: 17/9/2007 (dd/mm/yyyy)
Level: Damn hard, a lot of experience and luck are required
Language: English Image:Flag_English.gif
Comments:



ECG a short filtering tutorial

The ECG is a voltage difference, recorded between two metal plates or electrodes on the surface of the body, usually on two limbs. Different pairs of electrodes are used to record signals described as "Lead I", "Lead II" and "Lead III". For example, Lead I records the voltage at the Left Arm minus the voltage at the Right Arm. The 3 patterns are shown on the diagram. There is a standard colour code for connecting wires to the electrodes on each limb. The class apparatus uses just one amplifier and a switch connects it in one of the 3 patterns. Note that on each lead the trace will go up when the "+" electrode is more positive than the "-" electrode. Signals the other way round will make the trace go down. Connect up the leads to your subject using electrode jelly (a strong salt solution) to make a low-resistance electrical contact. Put the electodes on "fleshy" rather than "bony" parts of the limbs to make the best contact. Otherwise, it doesn't matter where on a limb the electrodes go.

ECG shapes

A typical ECG tracing of a normal heartbeat (or cardiac cycle) consists of a P wave, a QRS complex and a T wave. A small U wave is normally visible in 50 to 75\% of ECGs. The baseline voltage of the electrocardiogram is known as the isoelectric line. Typically the isoelectric line is measured as the portion of the tracing following the T wave and preceding the next P wave.

How to choose the channel

Once we acquired the ecg (sampled at Fs=1kHz)recordings data (from the Minimalist ECG interface), using the load command, it's useful to split the matrix in 4 vectors: 1 for the time and the other 3 for the voltage signals in triangular configuration (I,II,III).

clf
clc

%import the data into the workspace
%load ecg1ms.dat

chan1=ecg1ms(:,2);
chan2=ecg1ms(:,3);
chan3=ecg1ms(:,4);
time=ecg1ms(:,1)
figure(1)
subplot(3,1,1)
plot(time,chan1);
xlabel('Time');
title('channel 1');
subplot(3,1,2)
plot(time,chan2);
xlabel('Time');
title('channel 2');
subplot(3,1,3)
plot(time,chan3);
xlabel('Time');
title('channel 3');

avg1=mean(chan1);
pp1=max(chan1)-min(chan1);
fprintf('Amplitude factor channel 1 %f \n',pp1/avg1);
avg2=mean(chan2);
pp2=max(chan2)-min(chan2);
fprintf('Amplitude factor channel 2 %f \n',pp2/avg2);
avg3=mean(chan3);
pp3=max(chan2)-min(chan2);
fprintf('Amplitude factor channel 3 %f \n',pp3/avg3);

[val,index]=max([pp1,pp2,pp3]);
disp(['Channel with biggest amplitude is ,',num2str(index),'\n']);

To choose the signal with the biggest amplitude an amplitude factor is computed as ampF=max(channel)-min(channel)/mean(channel). In this way the average of the signal is considered (it could be also avoided since the signals have more or less the same drift). As we can see the channel with the biggest peak to peak amplitude is channel 2. The loaded signals are shown in figure

Image:Ecg_esempio.jpg

The recorded signals are produced by an ADC of 12 bit of resolution and preamplified of K=1000. The ADC resolution is given by:

with Vl=-4.096 and Vh=4.096.

Therefore to rebuild the original signal the equation is:

where i is the sample index. The matlab code follow:

clc
%clf
figure(3)
%import the data into the workspace
%load ecg1ms.dat

% First ECG sampled at 1 msec
Fs=1000; %Hz
Ts=1/Fs;
% Suppose the ADC convert to unsigned integer
digitalEcg=ecg1ms(:,index);
digits=12;
Vlow=-4.096;
Vhigh=+4.096;
ADCres=(Vhigh-Vlow)/(2^digits);

fprintf('ADC resolution is %8.2f \n', ADCres);
K=1000;
% The original signal is reconstructed
ecg=(digitalEcg*ADCres+Vlow)/K;
% Samples are spaced by the Ts quantity in seconds
tmax=(time(end)-time(1))*Ts
tsec=0:Ts:tmax;

figure(2)
subplot(2,1,1)
% A formatted signal
ecgformat=ecg(1:length(tsec));
ecgformat=ecg.*1e3;
grid on
plot(tsec,ecgformat);
xlabel('Time in seconds');
ylabel(' ECG mV');
title('Original Signal')
subplot(2,1,2)
fftPlot(tsec,ecg);
grid on;

title('Monolateral FFT');

The function to calculate the monolateral FFT get as parameters: the time partition and the signals to be analyzed. It plots the magnitude of the FFT coefficients.

function [fss,halfASpect]=fftPlot(tsec,ecg)
% Compute the FFT on the sampled signal
fftSpect=fft(ecg);
% number of samples are
nsamp=length(tsec);
% The fft transform coeffs are simmetric so we take only the half
hindex=ceil(nsamp/2);
halfSpect=zeros(1,hindex);
halfSpect(1:hindex)=(nsamp/2)*fftSpect(1:hindex);
% The frequency intervals are spaced by deltaF
% The fft consider the signal as periodic: in our case the signal last for
% tsec(end) approx 32 seconds
deltaFs=1/tsec(end);
fss=0:deltaFs:(hindex-1)*deltaFs;
halfASpect=abs(halfSpect);
plot(fss,halfASpect);
xlabel('Frequency   (Hz)');
ylabel('FFT magnitude');
end

for the monolateral FFT transform it's necessary only half of the coefficients (they are symmetric) and to scale them by a factor of $L=(number of samples)/2$. In figure:

Image:Ecg_originalfft.jpeg

we can see the original signal and the corresponding spectrum.

Display the original ECG and the spectrum

As we can see in the spectrum there's a predominant DC component and the 50 Hz component that represents the network power component for the ecg recording instrument. Other spurious components are present due to the radio interference, cross channel interference. An other low frequencies contribute (around 0.05 Hz) comes from the capacitive effect between the electrode and the skin which have different dielectric constants: in our case the contribute is really small because the used electrodes didn't have so much liquid glue. A zoomed version of the spectrum:

Image:Ecg_zoomedfft.jpg

Designing a FIR filter to remove DC and 50 Hz hum

To remove the 50Hz component a FIR stop band filter is needed. The matlab code is:

clc
%clf
figure(4)
% A FIR stop band filter required to remove the 50 Hz component
% Cutoff frequency
fsHalf=Fs/2;
wl=48/fsHalf;
wh=51/fsHalf;
stop50=fir1(1536,[wl wh],'stop');
ecgno50=filter(stop50,1,ecg);
subplot(2,1,1)
plot(tsec,ecgno50.*1e3,'r');
title('ECG without 50 Hz component');
xlabel('Time seconds');
ylabel('mV');
grid on
subplot(2,1,2)
fftPlot(tsec,ecgno50);
title('FFT of the filtered signal')
grid on;
fprintf('50 Hz filtered component is %f \n',122.9);

Remember to normalize the cutt off frequency in the range $0<\omega<1.0$ where $1.0$ is relative to the $F_{s}/2$. In figure we can see the cleaned signal and its relative spectrum. The order ofthe filter was chosen by trial and errors: starting from lower orders like 64, it was increased until the corresponding 50 Hz component in the fft trasform was reduced (before the filtering was after was $K_{50}=122.9$ ). If the order is bigger like $n=2000$ (a part of the computational issue) the phase response of the filter becomes not linear, therefore distortion will arise in the filtered ecg \ref{fig:5}. The signal is filtered and then the spectrum could be used to verify the cleaned signal.

Image:Ecg_filteredno50.jpeg
Filtered ecg: 50 Hz component deleted using a FIR stop band filter

The filter response of the FIR band pass filter is in figure 4:

Image:Ecg_stopfreqz1536.jpeg
FIR stop band filter of 1536th order

Increasing the order we can see how the phase becomes not linear:

FIR stop band filter of 2048 order

To remove the DC drift, an high pass filter is needed. The procedure is the same as previously described:

clc
%clf
figure(5)
% A FIR stop band filter required to remove the 50 Hz component
% Cutoff frequency
fsHalf=Fs/2;
wcutt=1/fsHalf;
highpass=fir1(2000,wcutt,'high');
ecgnoDC=filter(highpass,1,ecgno50);
subplot(2,1,1)
plot(tsec,ecgnoDC.*1e3,'r');
%axis([3 3.5])
title('ECG without DC drift');
xlabel('Time seconds');
ylabel('mV');
grid on
subplot(2,1,2)
[fss,coeff]=fftPlot(tsec,ecgnoDC);
title('FFT of the filtered signal')
grid on;
%freqz(highpass);
% Dc component is 271.884484
fprintf('DC filtered component is %f \n',coeff(1));

The cutoff frequency for the high pass filter was chosen as $f_{cutt}=1 Hz$. The DC component was reduced to $K_{ds}=271.884484$, as we can see in fig. 6.

Image:Ecg_filterednoDC.jpeg
Filtered ecg: DC component deleted using a fir %%% high pass filter of 2000th order

The response of this filter is in figure and the phase is still linear. Image:Ecg_highpassfreq2000.jpeg
Filtered ecg: high pass FIR of 2000th order

Now it's time to check if the signal was distorted but as we designed filters with a linear phase response, the ecg should be fine. In figure 8, we can recognize the P, QRS, T signals. The P component is smaller than T as expected.

Image:Ecg_zoomfirecg.jpeg
Filtered ecg: zoomed between 4 and 6 seconds

Designing a IIR filter to remove DC and 50 Hz hum

The FIR filter have the drawback of an high order: using a digital filter of 2000 slows down the overal performance. IIR filters wit the same specification have a low order but a general non linear phase response. In this example a Butterworth filter is used:

clc
%clf
figure(4)
% A FIR stop band filter required to remove the 50 Hz component
% Cutoff frequency
fsHalf=Fs/2;

% % Design a bandpass filter with passband of 48 Hz to 51 Hz, with less than
% 4 dB of ripple in the passband, and %20 dB attenuation in the stopbands that
% are 50 Hz wide on both sides of the passband. The sampling frequency is %
% 1kHz:

Wp = [49 51]/fsHalf; Ws = [48 52]/fsHalf;
Rp = 4; Rs = 20;

% % Calculate the minimum order of Butterworth filter required to meet the
% filter design specifications
[n,Wn] = buttord(Wp,Ws,Rp,Rs)
% Where: n is the filter order and Wn the normalised cut-off frequencies
fprintf('The filter order is %f',n);
% Order is 4

% Design the Butterworth filter
[b,a] = butter(n,Wn,'stop');

% % Plot the frequency response
% % Freqz uses an FFT to estimate the frequency response. In this example
% 1024 is the size of the FFT used.
freqz(b,a,1024,Fs)
pause(4)
% If you run this code in Matlab, you will see the filter order (n) is 2.
% Where did you get an order of 50 from? If I take your code and reduce the
% order to say 5, the result is more realistic.

% In order to apply this filter design to a signal, simply use:

ecgno50 = filter(b,a,ecg);

subplot(2,1,1)
plot(tsec,ecgno50.*1e3,'r');
title('ECG without 50 Hz component');
xlabel('Time seconds');
ylabel('mV');
grid on
subplot(2,1,2)
fftPlot(tsec,ecgno50);
title('FFT of the filtered signal')
grid on;
%freqz(stop50);
fprintf('50 Hz component is reduced to 5');

In this case I've chosen a passband of 48 Hz to 51 Hz, with less than 4 dB of ripple in the passband, and \%20 dB attenuation in the stopbands. The order of the stop pass filter is 4, compared to the 1350 of the corresponding FIR filter. The figure \ref{fig:9} shows the filtered ecg signals without the 50 Hz hum

Image:Ecg_filteredno50IIR.jpeg
Filtered 50 Hz component with a stop pass IIR filter

The filter response is shown in \ref{fig:10} and as we can see the phase is not linear, but the 50 Hz coefficient in the spectrum is reduced to $K_{50 IIR}5$ very small compared to the fir equivalent $K_{50}=122.9$.

Image:Ecg_butterstop.jpeg
Stop pass IIR Butterworth filter response

To design the corresponding high pass filter to remove the DC component:

clc
%clf
figure(5)
% A FIR stop band filter required to remove the 50 Hz component
% Cutoff frequency
fsHalf=Fs/2;
wcutt1=2/fsHalf;
wcutt2=4/fsHalf;
% % Design a bandpass filter with passband of 48 Hz to 51 Hz, with less than
% 4 dB of ripple in the passband, and %20 dB attenuation in the stopbands that
% are 50 Hz wide on both sides of the passband. The sampling frequency is %
% 1kHz:

Rp = 10; Rs = 28;

% % Calculate the minimum order of Butterworth filter required to meet the
% filter design specifications
[n,Wn] = buttord(wcutt1,wcutt2,Rp,Rs)
% Where: n is the filter order and Wn the normalised cut-off frequencies

% Design the Butterworth filter
[b,a] = butter(n,Wn,'high');
fprintf('The filter order is %f',n);

%%Filter order is 4
% % Plot the frequency response
% % Freqz uses an FFT to estimate the frequency response. In this example
% 1024 is the size of the FFT used.
freqz(b,a,1024,Fs)
pause(1);
ecgnoDC=filter(b,a,ecgno50);
subplot(2,1,1)
plot(tsec,ecgnoDC.*1e3,'r');
title('ECG without DC drift');
xlabel('Time seconds');
ylabel('mV');
grid on
subplot(2,1,2)
[ffs,coeff]=fftPlot(tsec,ecgnoDC);
title('FFT of the filtered signal')
grid on;
%%DC filtered component is 27.153459
fprintf('DC filtered component is %f \n',coeff(1));

The DC coefficient in the spectrum is greatly reduced to $27.1543459$. The filtered signal is shown:

Image:Ecg_filterednoDCIIR.jpeg
Cleaned ecg signal: no dc no 50 hum

The filter response is shown in fig:

Image:Ecg_butterFilterHigh.jpeg
Buttherworth high pass filter response

If we zoom to check the signal quality:

Image:Ecg_zoomIIRecg.jpeg
ECG cleaned signal

Comparing the 2 cases we can see that with the FIR approach the T signal is preserved while with the IIR approach the T signal has a negative peak, but the QRS signal is better filtered. The distorsion of the T signal is due to the non linearity of the phase response as already mentioned.

A different approach

Another different approach is to delete the FFT unwanted coefficients and reconstructing the original signal doing an inverse Fourier transform. The computational order is equal to where N is the number of samples.

Matlab code and data

Matlab code and an ecg recorded by a regular patient are provided here.


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.