Some experiments produce peaks that are distorted by being convoluted by processes that make peaks less distinct and modify peak position, height and width. Exponential broadening is one of the most common of these processes. Fourier deconvolution and iterative curve fitting are two methods that can help to measure the true underlying peak parameters. Those two methods are conceptually distinct, because in Fourier deconvolution, the underlying peak shape is unknown but the nature and width of the broadening function (e.g. exponential) is assumed to be known; whereas in iterative least-squares curve fitting it's just the reverse: the underlying peak shape (i.e. Gaussian, Lorentzian, etc) must be known, but the width of the broadening process is initially unknown.
In the script shown below and the resulting graphic shown on the right (Download this script), the underlying signal (uyy) is a set of four Gaussians with peak heights of 1.2, 1.1, 1, 0.9 located at x=10, 20, 30, 40 and peak widths of 3, 4, 5, 6, but in the observed signal (yy) these peaks are broadened exponentially by the exponential function cc, resulting in shifted, shorter, and wider peaks, and then a little constant white noise is added after the broadening. The deconvolution of cc from yy successfully removes the broadening (yydc), but at the expense of a substantial noise increase. However, the extra noise in the deconvoluted signal is high-frequency weighted ("blue") and so is easily reduced by smoothing and has less effect on least-square fits than does white noise. (For a greater challenge, try adding more noise in line 6 or use a bad estimate of time constant in line 10). To plot the recovered signal overlaid with underlying signal: plot(xx,uyy,xx,yydc). To plot the observed signal overlaid with the underlying signal: plot(xx,uyy,xx,yy). Excellent values for the original underlying peak positions, heights, and widths can be obtained by curve-fitting the recovered signal to four Gaussians: [FitResults,FitError]= peakfit([xx;yydc],26,42,4,1,0,10). With ten times the previous noise level (Noise=.01), the values of peak parameters determined by curve fitting are still quite good, and even with 100x more noise (Noise=.1) the peak parameters are more accurate than you might expect for that amount of noise (because that noise is blue). Visually, the noise is so great that the situation looks hopeless, but the curve-fitting actually works pretty well.
xx=5:.1:65;
% Underlying Gaussian peaks with unknown heights,
positions, and widths.
uyy=modelpeaks2(xx,[1
1 1 1],[1.2 1.1 1 .9],[10 20 30 40],[3 4 5 6],...
[0 0 0 0]);
% Observed signal yy, with noise added AFTER the broadening
convolution
Noise=.001; % <---Try more noise to see how this method
handles it.
yy=modelpeaks2(xx,[5 5 5 5],[1.2 1.1 1 .9],[10 20 30
40],[3 4 5 6],...
[-40 -40 -40 -40])+Noise.*randn(size(xx));
% Compute transfer function, cc,
cc=exp(-(1:length(yy))./40); % <---Change exponential
time constant here
% Attempt to recover original signal uyy by deconvoluting
cc from yy
% It's necessary to zero-pad the observed signal
yy as shown here.
yydc=deconv([yy zeros(1,length(yy)-1)],cc).*sum(cc);
% Plot and label everything
subplot(2,2,1);plot(xx,uyy);title('Underlying signal,
uyy');
subplot(2,2,2);plot(xx,cc);title('Exponential transfer
function, cc')
subplot(2,2,3);plot(xx,yy);title('observed broadened,
noisy signal, yy');
subplot(2,2,4);plot(xx,yydc);title('Recovered signal,
yydc')
An alternative to
the above deconvolution approach is to curve fit the
observed signal directly with an exponentially broadened Gaussian
(shape number 5): [FitResults,FitError]=peakfit([xx;yy],26,50,4,5,40,10).
Both methods give good values of the peak parameters, but
the deconvolution method is considerably faster, because
curve fitting with a simple Gaussian model is faster than
fitting with a exponentially broadened peak model,
especially if the number of peaks is large. Also, if the
exponential factor is not known, it can be determined by
curve fitting one or two of the peaks in the observed
signal, using ipf.m, adjusting the exponential factor
interactively to get the best fit. Note that you have to give
peakfit a reasonably good value for the time constant
('extra'), the input argument
right after the peakshape number. If the value is too
far off, the fit may fail completely, returning all zeros. A
little trial and error suffice. Alternatively, you could try
to use peakfit.m
version 7 with the independently
variable time constant exponentially-broadened
Gaussian
shape number 31 or 39, to measure the time constant as an
iterated variable (to understand the difference, see example 39). If the time
constant is expected to be the same for all peaks, better results
will be obtained by using shape number 31 or 39 initially to
measure the time constant of an isolated peak (preferably
one with a good S/N ratio), then apply that fixed time
constant in peak shape 5 to all the other groups of
overlapping peaks.
This page is part of "A Pragmatic Introduction to Signal
Processing", created and maintained by Tom O'Haver, Professor
Emeritus, Department of Chemistry and Biochemistry, The University
of Maryland at College Park. Comments, suggestions and questions
should be directed to Prof. O'Haver at toh@umd.edu. Updated July, 2022.