MATLAB: filter noisy EKG signal - matlab

What is the best filter to use to remove noise from an ECG signal with matlab?

If you have access to the Signal Processing Toolbox, then check out the Savitzky-Golay filter, namely the function sgolay. There's an accompanying demo, just run sgolaydemo.
The following is an example to show the various ways you can apply filtering and de-noising to a signal. Note some of these functions requires certain toolboxes to be present:
% load ecg: simulate noisy ECG
Fs=500;
x = repmat(ecg(Fs), 1, 8);
x = x + randn(1,length(x)).*0.18;
% plot noisy signal
figure
subplot(911), plot(x), set(gca, 'YLim', [-1 1], 'xtick',[])
title('noisy')
% sgolay filter
frame = 15;
degree = 0;
y = sgolayfilt(x, degree, frame);
subplot(912), plot(y), set(gca, 'YLim', [-1 1], 'xtick',[])
title('sgolayfilt')
% smooth
window = 30;
%y = smooth(x, window, 'moving');
%y = smooth(x, window/length(x), 'sgolay', 2);
y = smooth(x, window/length(x), 'rloess');
subplot(913), plot(y), set(gca, 'YLim', [-1 1], 'xtick',[])
title('smooth')
% moving average filter
window = 15;
h = ones(window,1)/window;
y = filter(h, 1, x);
subplot(914), plot(y), set(gca, 'YLim', [-1 1], 'xtick',[])
title('moving average')
% moving weighted window
window = 7;
h = gausswin(2*window+1)./window;
y = zeros(size(x));
for i=1:length(x)
for j=-window:window;
if j>-i && j<(length(x)-i+1)
%y(i) = y(i) + x(i+j) * (1-(j/window)^2)/window;
y(i) = y(i) + x(i+j) * h(j+window+1);
end
end
end
subplot(915), plot( y ), set(gca, 'YLim', [-1 1], 'xtick',[])
title('weighted window')
% gaussian
window = 7;
h = normpdf( -window:window, 0, fix((2*window+1)/6) );
y = filter(h, 1, x);
subplot(916), plot( y ), set(gca, 'YLim', [-1 1], 'xtick',[])
title('gaussian')
% median filter
window = 15;
y = medfilt1(x, window);
subplot(917), plot(y), set(gca, 'YLim', [-1 1], 'xtick',[])
title('median')
% filter
order = 15;
h = fir1(order, 0.1, rectwin(order+1));
y = filter(h, 1, x);
subplot(918), plot( y ), set(gca, 'YLim', [-1 1], 'xtick',[])
title('fir1')
% lowpass Butterworth filter
fNorm = 25 / (Fs/2); % normalized cutoff frequency
[b,a] = butter(10, fNorm, 'low'); % 10th order filter
y = filtfilt(b, a, x);
subplot(919), plot(y), set(gca, 'YLim', [-1 1])
title('butterworth')

Two filter design tools/demos that you may want to check out:
FDATool in the Signal Processing Toolbox (if you have access to it).
Analog Filter Design Toolbox from James Squire on the MathWorks File Exchange. There appear to be simulations for fitering EKG data included in the toolbox.
These should give you a chance to try out different filters and filter parameters to see how they perform with EKG/ECG data.

Related

Order area plots by their visible area, to maximize displayed information

I'm trying to plot a series of area plots in front of each others (not stacked). The problem is they sometimes hide each other. Take a look at this example:
clc; close all; clear variables;
%% generate some data
p = {[0 1 0 1.1];
[0 1 0 1];
[0 1 0 0.2];
[0.1 0.9 0 1.1]};
t = linspace(0, 2*pi);
y = cell2mat(cellfun(#(p) abs(p(1) + p(2)*sin(p(3)+p(4)*t)), p, 'UniformOutput', 0));
%% area plots without any order
n = size(p, 1);
C = lines(n);
h(1) = figure; hold on
for i=1:n
area(t, y(i, :), 'facecolor', C(i, :))
end
I tried to sort surfaces by their area to get a better result:
%% order surfaces by their area
integral = sum(y, 2);
[~, order] = sort(integral, 'descend');
h(2) = figure; hold on
for i=1:n
area(t, y(order(i), :), 'facecolor', C(order(i), :))
end
But the result is not satisfactory yet. I think the objective here is to maximize the area of least visible surface.
%% order surfaces by VISIBLE area
betterOrderIMO = [3 1 4 2 ];
h(3) = figure; hold on
for i=1:n
area(t, y(betterOrderIMO(i), :), 'facecolor', C(betterOrderIMO(i), :))
end
%% test visible area
N = zeros(3, n);
C = floor(C*256);
for i=1:3
f = getframe(h(i));
I = (f.cdata);
for j=1:n
N(i, j) = sum(sum(I(:, :, 1)==C(j, 1)& I(:, :, 2)==C(j, 2)&I(:, :, 3)==C(j, 3)));
end
end
min(N, [], 2)
ans = -> No. of pixels of the least visible surface
2363 -> not ordered
3034 -> ordered by area
4146 -> ordered manually
I can run an optimization (e.g. ga), but that seems overkill.
So are there any other options to get the bast order of a series of area plots, that maximizes the area of least visible plot?
It appears that your problem is to display a lot of signals/functions at the same time, based on your comments. How about you use a 3-dimensional perspective?
%% generate some data
p = {[0 1 0 1.1];
[0 1 0 1];
[0 1 0 0.2];
[0.1 0.9 0 1.1]};
t = linspace(0, 2*pi);
y = cell2mat(cellfun(#(p) abs(p(1) + p(2)*sin(p(3)+p(4)*t)), p, 'UniformOutput', 0));
%% area plots without any order
n = size(p, 1);
C = lines(n);
h(1) = figure; hold on
for i=1:n
patch( i*ones([1 numel(t)+2]), [t(1) t t(end)], [0 y(i,:) 0], C(i,:) );
end
view(3);
grid on;
You may want to replace the tick labels along the x axis with something more meaningful.
Another option would be this:
%% generate some data
p = {[0 1 0 1.1];
[0 1 0 1];
[0 1 0 0.2];
[0.1 0.9 0 1.1]};
t = linspace(0, 2*pi);
y = cell2mat(cellfun(#(p) abs(p(1) + p(2)*sin(p(3)+p(4)*t)), p, 'UniformOutput', 0));
%% area plots without any order
n = size(p, 1);
C = lines(n);
h(1) = figure;
h_patch=waterfall( [t(1) t t(end)], 1:n, [zeros([n 1]) y zeros([n 1])], (1:n).'.*ones([n numel(t)+2]) );
colormap(C);
set(h_patch,'FaceColor','none');
set(h_patch,'LineWidth',2);
view(-15,75);

Octave: How can I fit a sinusoid to my data using Octave?

My goal is to fit a sinusoid to data goming from a datalogger using Octave.
The datalogger logs force which is produced using an excenter, so it theoretically should be a sine wave.
I could not find any hint on how to do this elsewhere.
Currently I'm using the function "splinefit" followd by "ppval" to fit my data but I don't realy get the results I hoped from it...
Has anybody an idea how I could fit a sinusoid to my data?
Here's my current code I use to fit the data and a scrennshot of the result:
## splinefit force left
spfFL = splinefit(XAxis,forceL,50);
fitForceL=ppval(spfFL,XAxis);
##middle force left
meanForceL=mean(fitForceL);
middleedForceL=fitForceL-meanForceL;
result spline fit
on the X-Axis I have the 30'000 measurepoints or logs
on the Y-Axis I have the actual measured force values
the data comes from the datalogger in a .csv-file like this
You can do a simple regression using the sine and cosine of your (time) input as your regression features.
Here's an example
% Let's generate a dataset from a known sinusoid as an example
N = 1000;
Range = 100;
w = 0.25; % known frequency (e.g. from specs or from fourier analysis)
Inputs = randi(Range, [N, 1]);
Targets = 0.5 * sin( w * Inputs + pi/3 ) + 0.05 * randn( size( Inputs ) );
% Y = A + B sin(wx) + C cos(wx); <-- this is your model
Features = [ ones(N, 1), sin(w * Inputs), cos(w * Inputs) ];
Coefs = pinv(Features) * Targets;
A = Coefs(1); % your solutions
B = Coefs(2);
C = Coefs(3);
% print your nice solution against the input dataset
figure('position', [0, 0, 800, 400])
ax1 = axes()
plot(Inputs, Targets, 'o', 'markersize', 10, ...
'markeredgecolor', [0, 0.25, 0.5], ...
'markerfacecolor', [0, 0.5, 1], ...
'linewidth', 1.5)
set(ax1, 'color', [0.9, 0.9, 0.9])
ax2 = axes()
X = 1:0.1:Range;
plot( X, A + B*sin(w * X) + C*cos(w * X), 'k-', 'linewidth', 5 ); hold on
plot( X, A + B*sin(w * X) + C*cos(w * X), 'g-', 'linewidth', 2 ); hold off
set(ax2, 'xlim', get(ax1, 'xlim'), 'ylim', get(ax1, 'ylim'), 'color', 'none')
You could do a least squares optimization, using fminsearch
% sine to fit (in your case your data)
x = 0:0.01:50;
y = 2.6*sin(1.2*x+3.1) + 7.3 + 0.2*rand(size(x)); % create some noisy sine with known parameters
% function with parameters
fun = #(x,p) p(1)*sin(p(2)*x+p(3)) + p(4); % sine wave with 4 parameters to estimate
fcn = #(p) sum((fun(x,p)-y).^2); % cost function to minimize the sum of the squares
% initial guess for parameters
p0 = [0 0 0 0];
% parameter optimization
par = fminsearch(fcn, p0);
% see if estimated parameters match measured data
yest = fun(x, par)
plot(x,y,x,yest)
Replace x and y with your data. The par variable contains the parameters of the sine, as defined in fun.

How to set background in multiple colors in semilogy plot (MATLAB) ?

I am looking for a way to shade the background of my semilog plot in two colors.
For example, in the following image, I have am plotting three polynomials and they all are equal at x=1. I want one rectangle for x<1 region and other for x>1 region. How can I insert two such rectangles, of different colors, in background to highlight these two regions.
MWE:
x = 0.1:0.1:10;
y1 = polyval([1, 0], x); % Evaluate y = x;
y2 = polyval([1, 0, 0], x); % Evaluate y = x^2;
y3 = polyval([1, 0, 0, 0], x); % Evaluate y = x^3;
figure
semilogy(x, y1, '.k', x, y2, '.b', x, y3, '.r'); title ('Three
polynomials on a semilog y scale') xlabel('x'); ylabel('y');
legend({'y= x', 'y = x^2', 'y = x^3'}, 'Location', 'Northwest')
You can solve that using area or patch.
As pointed by #SardarUsama, there are others questions with good examples on it, however, you need to avoid to have any zeros in the area data, otherwise it will fail.
Follows the code setting one area only.
x = 0.1:0.1:10;
y1 = polyval([1, 0], x); % Evaluate y = x;
y2 = polyval([1, 0, 0], x); % Evaluate y = x^2;
y3 = polyval([1, 0, 0, 0], x); % Evaluate y = x^3;
figure
plot(x, y1, '.k', x, y2, '.b', x, y3, '.r'); %MODIFIED
hold on %ADDED
title ('Three polynomials on a semilog y scale')
set (gca, 'Yscale', 'log'); %ADDED
xlabel('x');
ylabel('y');
legend({'y= x', 'y = x^2', 'y = x^3'}, 'Location', 'Northwest')
area( [1 1 10 10],[1e-3 1e+3 1e+3 1e-3 ],'FaceColor','green','facealpha',0.3) %ADDED
The code above works for matlab after 2014b. If you have one before that, you can use the patch function (which requires some small change in the data, but uses the Facealpha option) or you can move the area to the background as i do below:
ax=get(gca,'Children'); %ADDED
set(gca,'Children',[ax(2) ax(3) ax(4) ax(1)]); %ADDED, move area to background
Note: Indeed, I missed the problem with the legend. I correct as mentioned, however for me the area was on top of the other graphs. To solve it i changed the order of the plots. If the area was with transparency, this will not be an issue.

Filling an area above a curve with many colors (matlab, surf)

I'm trying to create a figure in matlab that looks like this:
desired figure
I am doing so by: (i) assigning value points to each x,y coordinate, (ii) plotting a surf, and (iii) change the view point so the third axis is not seen. Here is the code:
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
z = linspace(0, 1, 10);
z = repmat(z, 10, 1);
z = flipud(triu(z));
z(z==0) = nan;
hold off
surf(x, y, z, 'linestyle', 'none')
colormap([linspace(0.39, 1, 20)',linspace(0.58, 0.25, 20)', linspace(0.93, 0.25, 20)']);
colorbar
xlim([x(1) x(end)])
shading interp
view([90 -90])
hold on
plot(x, 1-y, 'linewidth', 2)
I get the following figure: matlab figure I get
As you can see, there a lot of white spaces above the line which I would like to be in color as well. Unfortunately, I cannot add any more grid points as calculating the actual value of the points takes a lot of time (unlike the example above).
Is there a way to have matlab draw colors in those white spaces as well?
Thanks!
You can try to use patch function to create filled polygon.
See http://www.mathworks.com/help/matlab/ref/patch.html
Try the following code:
vert = [0 1;1 1;1 0]; % x and y vertex coordinates
fac = [1 2 3]; % vertices to connect to make triangle
fvc = [1 0 0; 1 1 1; 0 0 1];
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp');
Result is close:
I was managed to get closer to the desired figure:
close all
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
%colorbar
xlim([x(1) x(end)])
%Fill rectangle.
vert = [0 0; 1 0; 1 1; 0 1]; % x and y vertex coordinates
fac = [1 2 3 4]; % vertices to connect to make squares
%patch('Faces',fac,'Vertices',vert,'FaceColor','red')
fvc = [1 0 0; 0.6 0.7 1; 0.6 0.7 1; 1 0 0]; %Color of vertices (selected to be close to example image).
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp')
hold on
%Fill lower triangle with white color.
vert = [0 0;0 1;1 0]; % x and y vertex coordinates
fac = [1 2 3]; % vertices to connect to make triangle
fvc = [1 1 1; 1, 1, 1; 1, 1, 1]; %White color
patch('Faces',fac,'Vertices',vert,'FaceVertexCData',fvc,'FaceColor','interp');
plot(x, 1-y, 'linewidth', 2)
set(gca,'Xtick',[],'Ytick',[]); %Remove tick marks
Result:
Thank you Rotem! I wasn't aware of the patch function and indeed it solved the issue!
The colors on the actual figure I'm trying to achieve are not linear, so I just used patch for all the empty triangles. Here is the adjusted code I use for the simple example (again, this is just a bit more general just to be able to have non linear colors in the area above the curve):
x = linspace(0, 1, 10);
y = linspace(0, 1, 10);
z = linspace(0, 1, 10);
z = repmat(z, 10, 1)+0.1;
z = flipud(triu(z));
z(z==0) = nan;
z = z-0.1;
hold off
surf(x, y, z, 'linestyle', 'none')
colormap([linspace(0.39, 1, 20)',linspace(0.58, 0.25, 20)', linspace(0.93, 0.25, 20)']);
colorbar
xlim([x(1) x(end)])
shading interp
view([90 -90])
hold on
patch_cor_y = kron((length(y):-1:1)', ones(3, 1));
patch_cor_x = kron((1:length(x))', ones(3, 1));
patch_cor = [y(patch_cor_y(2:end-2))', x(patch_cor_x(3:end-1))'];
patch_path = reshape(1:length(patch_cor),3, length(patch_cor)/3)';
patch_col = z(sub2ind(size(z), patch_cor_x(3:end-1), patch_cor_y(2:end-2)));
patch('Faces',patch_path,'Vertices',patch_cor,'FaceVertexCData',patch_col,'FaceColor','interp', 'EdgeColor', 'none');
plot(x, 1-y, 'linewidth', 2)
The figure achieved: figure

Multi dimensional (2d better 3d) scatter-plot with different errorbars in matlab

I am trying to program scatterplot with specific errorbars. The only build in function i found is
errorbar()
but this only enables me to make a 2d plot with errorbars in y direction. What i am asking for is a method to plot this with errorbars in x and y direction.
At the end my goal is to make a 3D-scatter-plot with 3 errorbars.
Perfect would be if the resulting image would be a 3d-plot with 3d geometric shapes (coordinate x,y,z with expansion in the dimension proportional to the errorbars) as 'marker'.
I found this page while searching the internet: http://code.izzid.com/2007/08/19/How-to-make-a-3D-plot-with-errorbars-in-matlab.html
But unfortunately they use only one errorbar.
My data is set of 6 arrays each containing either the x,y or z coordinate or the specific standard derivation i want to show as errorbar.
The code you posted looks very easy to adapt to draw all three error bars. Try this (note that I adapted it also so that you can change the shape and colour etc of the plots as you normally would by using varargin, e.g. you can call plot3d_errorbars(...., '.r'):
function [h]=plot3d_errorbars(x, y, z, ex, ey, ez, varargin)
% create the standard 3d scatterplot
hold off;
h=plot3(x, y, z, varargin{:});
% looks better with large points
set(h, 'MarkerSize', 25);
hold on
% now draw the vertical errorbar for each point
for i=1:length(x)
xV = [x(i); x(i)];
yV = [y(i); y(i)];
zV = [z(i); z(i)];
xMin = x(i) + ex(i);
xMax = x(i) - ex(i);
yMin = y(i) + ey(i);
yMax = y(i) - ey(i);
zMin = z(i) + ez(i);
zMax = z(i) - ez(i);
xB = [xMin, xMax];
yB = [yMin, yMax];
zB = [zMin, zMax];
% draw error bars
h=plot3(xV, yV, zB, '-k');
set(h, 'LineWidth', 2);
h=plot3(xB, yV, zV, '-k');
set(h, 'LineWidth', 2);
h=plot3(xV, yB, zV, '-k');
set(h, 'LineWidth', 2);
end
Example of use:
x = [1, 2];
y = [1, 2];
z = [1, 2];
ex = [0.1, 0.1];
ey = [0.1, 0.5];
ez = [0.1, 0.3];
plot3d_errorbars(x, y, z, ex, ey, ez, 'or')