Need help to removing motion (breathing?) artifact from ECG signal
11 views (last 30 days)
Show older comments
Simone Arno
on 29 Aug 2024
Commented: Star Strider
on 30 Aug 2024
I have this single-channel ECG signal with motion artifacts (I believe from breathing).
I've tried several filters, but none have given me a good output.
Not being an expert, I followed the instructions from Kher, 2019 with this code, but a compatibility issue (since I am using version 2018b) prevents me from obtaining any results; by changing some commands the result is unsuitable:
y1 = load('EKG.mat');
y2= (y1 (:,1)); % ECG signal data
a1= (y1 (:,1)); % accelerometer x-axis data
a2= (y1 (:,1)); % accelerometer y-axis data
a3= (y1 (:,1)); % accelerometer z-axis data
y2 = y2/max(y2);
Subplot (3, 1, 1), plot (y2), title ('ECG Signal with motion artifacts'), grid on
a = a1+a2+a3;
a = a/max(a);
mu= 0.0008;
%Hd = adaptfilt.lms(32, mu); %original command
Hd = dsp.LMSFilter('Length', 32, 'StepSize', mu);
% [s2, e] = filter(Hd, a, y2); % original command, don't work in 2018b version
[s2, e] = Hd(a, y2); % command adapted
fig = figure
subplot (3, 1, 2)
plot (s2)
title ('Noise (motion artifact) estimate')
grid on
subplot (3, 1, 3)
plot (e)
title ('Adaptively filtered/ Noise free ECG signal')
grid on
I also tried filtering in this other way, but the result is very poor.
ecg_signal = load('EKG.mat');
Fs = 256;
t = (0:length(ecg_signal)-1) / Fs;
fc = 45; % cut frequency
[b, a] = butter(4, fc / (Fs / 2), 'low');
% filter
ecg_filtered = filtfilt(b, a, ecg_signal);
With simple low-pass or high-pass filters I wasn't able to obtain at least acceptable results.
If anyone can help me?
thank you in advance
4 Comments
Accepted Answer
Star Strider
on 29 Aug 2024
There does not appear to be much noise at all, however the small baseline variation and high-frequency noise can be eliminated with an appropriiately-designed bandpass filter.
Try this —
LD = load('EKG.mat')
EKG = LD.data256hz{:,1};
Fs = 256; % No Time Vector Supplied, So Create One
t = linspace(0, numel(EKG)-1, numel(EKG)).'/Fs;
figure
plot(t, EKG)
grid
xlim('tight')
xlabel('Time (s)')
ylabel('Amplitude (V)')
title('Unprocessed EKG Signal')
figure
plot(t, EKG)
grid
xlim([0 5])
xlabel('Time (s)')
ylabel('Amplitude (V)')
title('Unprocessed EKG Signal (Detail)')
[FTs1,Fv] = FFT1(EKG,t);
figure
plot(Fv, abs(FTs1)*2)
grid
xlim('tight')
xlabel('Frequency (Hz)')
ylabel('Magnitude (V)')
title('Fourier Transform')
figure
plot(Fv, abs(FTs1)*2)
grid
xlim([0 10])
xlabel('Frequency (Hz)')
ylabel('Magnitude (V)')
title('Fourier Transform (Detail)')
EKG = [ones(100,1)*EKG(1); EKG]; % Pre-Appeend 'ones' Veector To Eliiminate Starting Transient
EKG_filt = bandpass(EKG, [1, 45], Fs, 'ImpulseResponse','iir'); % Filter With Elliptic IIR Bandpass Filter
EKG_filt = EKG_filt(101:end);
figure
plot(t, EKG_filt)
grid
xlim([0 5])
xlabel('Time (s)')
ylabel('Amplitude (V)')
title('Bandpass-Filtered EKG Signal (Detail)')
function [FTs1,Fv] = FFT1(s,t)
% Arguments:
% s: Signal Vector Or Matrix
% t: Associated Time Vector
t = t(:);
L = numel(t);
if size(s,2) == L
s = s.';
end
Fs = 1/mean(diff(t));
Fn = Fs/2;
NFFT = 2^nextpow2(L);
FTs = fft((s - mean(s)) .* hann(L).*ones(1,size(s,2)), NFFT)/sum(hann(L));
Fv = Fs*(0:(NFFT/2))/NFFT;
% Fv = linspace(0, 1, NFFT/2+1)*Fn;
Iv = 1:numel(Fv);
FTs1 = FTs(Iv,:);
end
Use the Fourier transform results to guide the filter design.
.
2 Comments
Star Strider
on 30 Aug 2024
As always, my pleasure!
The ‘FFT1’ function is one I wrote, and appended at the end of the code I posted:
function [FTs1,Fv] = FFT1(s,t)
% Arguments:
% s: Signal Vector Or Matrix
% t: Associated Time Vector
t = t(:);
L = numel(t);
if size(s,2) == L
s = s.';
end
Fs = 1/mean(diff(t));
Fn = Fs/2;
NFFT = 2^nextpow2(L);
FTs = fft((s - mean(s)) .* hann(L).*ones(1,size(s,2)), NFFT)/sum(hann(L));
Fv = Fs*(0:(NFFT/2))/NFFT;
% Fv = linspace(0, 1, NFFT/2+1)*Fn;
Iv = 1:numel(Fv);
FTs1 = FTs(Iv,:);
end
Feel free to copy it and use it. If you save it as a separate file on your MATLAB search path, name that file FFT1.m.
.
More Answers (1)
Image Analyst
on 29 Aug 2024
I'm sure it's been done before. Rather than me just guessing, I suggest you search the medical literature in PubMed to find articles that show how it's done.
0 Comments
See Also
Categories
Find more on Single-Rate Filters in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!