Remove base line drift with peicewise cubic spline algorithm using MATLAB - matlab

I have a signal which I want to remove the basline drift using the picewise cubic spline algorithm in MATLAB.
d=load(file, '-mat');
t=1:length(a);
xq1=1:0.01:length(a);
p = pchip(t,a,xq1);
s = spline(t,a,xq1);
%
figure, hold on, plot(a, 'g'), plot(t,a,'o',xq1,p,'-',xq1,s,'-.')
legend('Sample Points','pchip','spline','Location','SouthEast')
But I cant see any basline removal..The orginal data is exactly on the interpolated one.
or in the other signal as we can see no base line is removed.
The question is how I can "use peicewise cubic spline interpolation to
remove basline drift" in MATLAB.
Thank you

It seems likely that you are looking to fit a polynomial to your data to estimate baseline drift due to thermal variations. The problem with spline is that it will always perfectly fit your data (similar to pchip) because it is an interpolation technique. You probably want a courser fit which you can get using polyfit. The following code sample shows how you could use polyfit to estimate the drift. In this case I fit a 3rd-order polynomial.
% generate some fake data
t = 0:60;
trend = 0.003*t.^2;
x = trend + sin(0.1*2*pi*t) + randn(1,numel(t))*0.5;
% estimate trend using polyfit
p_est = polyfit(t,x,3);
trend_est = polyval(p_est,t);
% plot results
plot(t,x,t,trend,t,trend_est,t,x-trend_est);
legend('data','trend','estimated trend','trend removed','Location','NorthWest');
Update
If you have the curve fitting toolbox you can fit a cubic spline with an extra smoothing constraint. In the example above you could use
trend_est = fnval(csaps(t,x,0.01),t);
instead of polyfit and polyval. You will have to play with the smoothing parameter, 0 being completely linear and 1 giving the same results as spline.

I think you should reduce the number of points at which you calculate the spline fit (this avoids over-fitting) and successively interpolate the fit on the original x-data.
t = 0:60;
trend = 0.003*t.^2;
x = trend + sin(0.1*2*pi*t) + randn(1,numel(t))*0.5;
figure;hold on
plot(t,x,'.-')
%coarser x-data
t2=[1:10:max(t) t(end)]; %%quick and dirty. You probably wanna do better than this
%spline fit here
p = pchip(t,x,t2);
s = spline(t,x,t2);
plot(t2,s,'-.','color' ,'g')
%interpolate back
trend=interp1(t2,s,t);
%remove the trend
plot(t,x-trend,'-.','color' ,'c')

Related

How to create a curve that will best fit the points in my plot

lmd = 10;
k = poissrnd(lmd,1,100000);
q = exp(-lmd).*((lmd.^k)./factorial(k));
plot(k,q,'.')
I cant connect my points through plot() since it comes out a jumbled mess. How can I plot a curve of the points I have that will best fit the data.
Use curve fitting toolbox of the MATLAB and it provides you with so many fitting options. You can find which option works best for you by try and error.
If you want to use spline, use yy=spline(x,y,xx) command. Then use plot(xx,yy) to plot the curve.
Sort the data
[x,i] = sort(k);
y = q(i);
plot(x,y);
If you have to "fit" the data, try cubic spline interpolation.

Matlab: plotting frequency distribution with a curve

I have to plot 10 frequency distributions on one graph. In order to keep things tidy, I would like to avoid making a histogram with bins and would prefer having lines that follow the contour of each histogram plot.
I tried the following
[counts, bins] = hist(data);
plot(bins, counts)
But this gives me a very inexact and jagged line.
I read about ksdensity, which gives me a nice curve, but it changes the scaling of my y-axis and I need to be able to read the frequencies from the y-axis.
Can you recommend anything else?
You're using the default number of bins for your histogram and, I will assume, for your kernel density estimation calculations.
Depending on how many data points you have, that will certainly not be optimal, as you've discovered. The first thing to try is to calculate the optimum bin width to give the smoothest curve while simultaneously preserving the underlying PDF as best as possible. (see also here, here, and here);
If you still don't like how smooth the resulting plot is, you could try using the bins output from hist as a further input to ksdensity. Perhaps something like this:
[kcounts,kbins] = ksdensity(data,bins,'npoints',length(bins));
I don't have your data, so you may have to play with the parameters a bit to get exactly what you want.
Alternatively, you could try fitting a spline through the points that you get from hist and plotting that instead.
Some code:
data = randn(1,1e4);
optN = sshist(data);
figure(1)
[N,Center] = hist(data);
[Nopt,CenterOpt] = hist(data,optN);
[f,xi] = ksdensity(data,CenterOpt);
dN = mode(diff(Center));
dNopt = mode(diff(CenterOpt));
plot(Center,N/dN,'.-',CenterOpt,Nopt/dNopt,'.-',xi,f*length(data),'.-')
legend('Default','Optimum','ksdensity')
The result:
Note that the "optimum" bin width preserves some of the fine structure of the distribution (I had to run this a couple times to get the spikes) while the ksdensity gives a smooth curve. Depending on what you're looking for in your data, that may be either good or bad.
How about interpolating with splines?
nbins = 10; %// number of bins for original histogram
n_interp = 500; %// number of values for interpolation
[counts, bins] = hist(data, nbins);
bins_interp = linspace(bins(1), bins(end), n_interp);
counts_interp = interp1(bins, counts, bins_interp, 'spline');
plot(bins, counts) %// original histogram
figure
plot(bins_interp, counts_interp) %// interpolated histogram
Example: let
data = randn(1,1e4);
Original histogram:
Interpolated:
Following your code, the y axis in the above figures gives the count, not the probability density. To get probability density you need to normalize:
normalization = 1/(bins(2)-bins(1))/sum(counts);
plot(bins, counts*normalization) %// original histogram
plot(bins_interp, counts_interp*normalization) %// interpolated histogram
Check: total area should be approximately 1:
>> trapz(bins_interp, counts_interp*normalization)
ans =
1.0009

How to produce a log scale FFT with MatLab

It's my first time performing an FFT within MatLab by experimenting with some example code from the MathWorks website. I was wondering if it was possible to take the code I have and transform the x axis to a log-scale representation rather than linear. I understand most of the code, but it is the x axis line of code that I'm still not 100% sure exactly what it is doing apart from the +1 at the end of the line, which is that fact that MatLab's indexing structure doesn't start on 0.
My code so far is:
[y,fs] = wavread('Wav/800Hz_2sec.wav');
NFFT = 4096;
Y = fft(y,NFFT)/length(y);
f = fs/2*linspace(0,1,NFFT/2+1);
plot(f,2*abs(Y(1:NFFT/2+1))
frequency usually comes out in linear scale from Discrete Fourier Transform. if you want, you can make a new frequency vector in log scale and interpolate the results you already have
fnew=fs/2.*logspace(log10(fs/length(y)),0,npts);
Ynew= interp1(f,Y(1:NFFT/2+1),fnew);
where npts is the length of your new frequency vector. for just plotting
loglog(f,2*abs(Y(1:NFFT/2+1));
honestly IMO, the interpolation thing doesn't work very well because FFT of real signals produces strong peaks and troughs in spectra, so unless you smooth your spectrum first, the interpolated spectrum won't look as nice

Extract data from curve fit toolbox

I am using matlab and I have a certain set of x and y data,
x=[0,1.25,1.88,2.5,5,6.25,6.88,7.19,7.5,10,12.5,15,20];
y=[-85.93,-78.82,-56.95,-34.56,-33.57,-39.64,-41.96,-49.28,-66.6,-66.61,-59.16,-48.78,-41.53];
I want to use the curve fitting toolbox which has the spline function to generate a graph, so i did this,
cftool
It would bring me to the toolbox which i can then choose the spline fit. I was thinking if its possible that i extract the data points from the spline graph generated. Which means i probably would have more x and y data points than those that i input in, since the spline graph is sort of a continuous graph. Anyone could give me some advice on this? Thanks!
You can perform the equivalent of the spline fit performed with cftool with fit, see for instance here, here, or here:
% perform spline fit without cftool
ft = fittype('cubicspline');
coeff=fit(x,y,ft);
% use plot to display the interpolating polynomial
% (relying on internal plot settings)
figure
h=plot(coeff,x,y,'o');
% extract the *interpolated* curve from the figure
xi=get(h,'XData');
yi=get(h,'YData');
Replot it just to show that we can:
But if you just want to interpolate do as Fraukje explained here. Define a finer grid on x and use the interp1 function, as in the following example (same x,y input data as before):
% interpolate
Ni = 100;
xi = linspace(x(1),x(end),Ni);
yi = interp1(x,y,xi,'spline');
Now xi,yi is the interpolated data:

Smoothing of histogram with a low-pass filter in MATLAB

I have an image and my aim is to binarize the image. I have filtered the image with a low pass Gaussian filter and have computed the intensity histogram of the image.
I now want to perform smoothing of the histogram so that I can obtain the threshold for binarization. I used a low pass filter but it did not work. This is the filter I used.
h = fspecial('gaussian', [8 8],2);
Can anyone help me with this? What is the process with respect to smoothing of a histogram?
imhist(Ig);
Thanks a lot for all your help.
I've been working on a very similar problem recently, trying to compute a threshold in order to exclude noisy background pixels from MRI data prior to performing other computations on the images. What I did was fit a spline to the histogram to smooth it while maintaining an accurate fit of the shape. I used the splinefit package from the file exchange to perform the fitting. I computed a histogram for a stack of images treated together, but it should work similarly for an individual image. I also happened to use a logarithmic transformation of my histogram data, but that may or may not be a useful step for your application.
[my_histogram, xvals] = hist(reshape(image_volume), 1, []), number_of_bins);
my_log_hist = log(my_histogram);
my_log_hist(~isfinite(my_log_hist)) = 0; % Get rid of NaN values that arise from empty bins (log of zero = NaN)
figure(1), plot(xvals, my_log_hist, 'b');
hold on
breaks = linspace(0, max_pixel_intensity, numberofbreaks);
xx = linspace(0, max_pixel_intensity, max_pixel_intensity+1);
pp = splinefit(xvals, my_log_hist, breaks, 'r');
plot(xx, ppval(pp, xx), 'r');
Note that the spline is differentiable and you can use ppdiff to get the derivative, which is useful for finding maxima and minima to help pick an appropriate threshold. The numberofbreaks is set to a relatively low number so that the spline will smooth the histogram. I used linspace in the example to pick the breaks, but if you know that some portion of the histogram exhibits much greater curvature than elsewhere, you'd want to have more breaks in that region and less elsewhere in order to accurately capture the shape of the histogram.
To smooth the histogram you need to use a 1-D filter. This is easily done using the filter function. Here is an example:
I = imread('pout.tif');
h = imhist(I);
smooth_h = filter(normpdf(-4:4, 0,1),1,h);
Of course you can use any smoothing function you choose. The mean would simply be ones(1,8).
Since your goal here is just to find the threshold to binarize an image you could just use the graythresh function which uses Otsu's method.