Resampling Nonuniformly Sampled Signals
This example shows how to resample nonuniformly sampled signals to a new uniform rate. It shows how to apply a custom filter on irregularly sampled data to reduce aliasing. It also shows how to use detrending to remove transients at the start and at the end of the signal.
Resampling Nonuniformly Sampled Signals to a Desired Rate
The resample
function allows you to convert a nonuniformly sampled signal to a new uniform rate.
Create a 500 Hz sinusoid sampled irregularly at about 48 kHz. We simulate the irregularity by adding random values to the uniform vector.
rng default nominalFs = 48000; f = 500; Tx = 0:1/nominalFs:0.01; irregTx = sort(Tx + 1e-4*rand(size(Tx))); x = sin(2*pi*f*irregTx); plot(irregTx,x,'.')
To resample a nonuniformly sampled signal, you can call resample
with a time vector input.
The next example converts our original signal to a uniform 44.1 kHz rate.
desiredFs = 44100; [y, Ty] = resample(x,irregTx,desiredFs); plot(irregTx,x,'.-',Ty,y,'o-') legend('Original','Resampled') ylim([-1.2 1.2])
You can see that our resampled signal has the same shape and size as the original signal.
Choosing an Interpolation Method
The conversion algorithm in resample
works best when the input samples are as close to regularly spaced as possible, so it is instructive to observe what may happen when a section of the input samples is missing from the sampled data.
The next example notches out the second crest of the input sinusoid and apply resampling.
irregTx(105:130) = []; x = sin(2*pi*f*irregTx); [y, Ty] = resample(x,irregTx,desiredFs); plot(irregTx,x,'. ') hold on plot(Ty,y,'.-') hold off legend('Original','Resampled') ylim([-1.2 1.2])
The missing segment is connected by linear interpolation. Linear interpolation is the default method used by the resample
function to resample nonuniformly sampled data.
In some cases where you have missing data or large gaps in your input, you can recover some of the missing data by choosing a different interpolation method.
For low-noise, low-bandwidth signals, splines can be very effective when used to reconstruct the original signal. To use a cubic spline during resampling, supply the 'spline' interpolation method:
[y, Ty] = resample(x,irregTx,desiredFs,'spline'); plot(irregTx,x,'. ') hold on plot(Ty,y,'.-') hold off legend('Original','Resampled using ''spline''') ylim([-1.2 1.2])
Controlling the Interpolation Grid
By default, resample
constructs an intermediate grid that is a close rational approximation of the ratio between the desired sample rate and the average sample rate of the signal.
If a section of your input samples contain high-frequency components, you can control the spacing of the intermediate grid by choosing integer coefficients, p
and q
, to select this rational ratio.
Examine the step response of an underdampened second order filter that oscillates at a rate of about 3 Hz:
w = 2*pi*3;
d = .1002;
z = sin(d);
a = cos(d);
t = [0:0.05:2 3:8];
x = 1 - exp(-z*w*t).*cos(w*a*t-d)/a;
plot(t,x,'.-')
The step response is sampled at a high rate where it is oscillating and at a low rate where it is not.
Now resample the signal at 100 Hz just using the default settings:
Fs = 100; [y, Ty] = resample(x,t,Fs); plot(t,x,'. ') hold on plot(Ty,y) hold off legend('Original','Resampled (default settings)')
The envelope of the oscillation at the start of the waveform is attenuated and oscillates more slowly than the original signal.
resample
, by default, interpolates to a grid of regularly spaced intervals that correspond to the average sample rate of the input signal.
avgFs = (numel(t)-1) /(t(end)-t(1))
avgFs = 5.7500
The sample rate of the grid should be higher than twice the largest frequency that you wish to measure. The sample rate of the grid, 5.75 samples per second, is below the Nyquist sample rate, 6 Hz, of the ringing frequency.
To make the grid have a higher sample rate, you can supply the integer parameters, p
and q
. resample
adjusts the sample rate of the grid to Q*Fs/P, interpolates the signal, and then applies its internal sample rate converter (upsampling by P and downsampling by Q) to recover the desired sample rate, Fs. Use rat
to select p
and q
.
Since the ringing of the oscillation is 3 Hz, specify the grid with a sample rate of 7 Hz, which is a little higher than the Nyquist rate. The headroom of 1 Hz accounts for additional frequency content due to the decaying exponential envelope.
Fgrid = 7; [p,q] = rat(Fs/Fgrid)
p = 100
q = 7
[y, Ty] = resample(x,t,Fs,p,q); plot(t,x,'.') hold on plot(Ty,y) hold off legend('Original','Resampled (custom P and Q)')
Specifying the Anti-Aliasing Filter
In the next example, you can view the output of a digitizer that measures the throttle setting on an airplane engine. The throttle setting is nonuniformly sampled about a nominal rate of 100 Hz. We will try to resample this signal at a uniform 10 Hz rate.
Here are the samples of our original signal.
load engineRPM plot(t,x,'.') xlabel('Time (s)') ylabel('RPM')
Our signal is quantized. Now zoom into the ascending region in the time interval from 20 seconds to 23 seconds:
plot(t,x,'.')
xlim([20 23])
The signal is slowly varying within this region. This allows you to remove some of the quantization noise by using the anti-aliasing filter in the resampler.
desiredFs = 10; [y,ty] = resample(x,t,desiredFs); plot(t,x,'.') hold on plot(ty,y,'.-') hold off xlabel('Time') ylabel('RPM') legend('Original','Resampled') xlim([20 23])
This works reasonably well. However, the resampled signal can be smoothed further by providing resample
a filter with a low cutoff frequency.
First, set the grid spacing to be about our nominal 100 Hz sample rate.
nominalFs = 100;
Next, determine a reasonable p
and q
to obtain the desired rate. Since the nominal rate is 100 Hz and our desired rate is 10 Hz, you need to decimate by 10. This is equivalent to setting p
to 1 and setting q
to 10.
p = 1; q = 10;
You can supply resample
with your own filter. To have proper temporal alignment, the filter should be of odd length. The filter length should be a few times larger than p
or q
(whichever is larger). Set the cutoff frequency to be 1 / q
desired cutoff and then multiply the resulting coefficients by p
.
% ensure an odd length filter n = 10*q+1; % use .25 of Nyquist range of desired sample rate cutoffRatio = .25; % construct lowpass filter lpFilt = p * fir1(n, cutoffRatio * 1/q); % resample and plot the response [y,ty] = resample(x,t,desiredFs,p,q,lpFilt); plot(t,x,'.') hold on plot(ty,y) hold off xlabel('time') ylabel('RPM') legend('Original','Resampled (custom filter)','Location','best') xlim([20 23])
Removing Endpoint Effects
Now zoom out to view our original signal. Note that there is significant offset at the endpoints.
plot(t,x,'.',ty,y) xlabel('time') ylabel('RPM') legend('original','resampled (custom filter)','Location','best')
These artifacts arise because resample
assumes that the signal is zero outside the borders of the signal. To reduce the effect of these discontinuities, subtract off a line between the endpoints of the signal, perform resampling, and then add back the line to the original function. You can do this by computing the slope and the offset of the line between the first and last sample, and using polyval
to construct the line to subtract.
% compute slope and offset (y = a1 x + a2) a(1) = (x(end)-x(1)) / (t(end)-t(1)); a(2) = x(1); % detrend the signal xdetrend = x - polyval(a,t); plot(t,xdetrend)
The detrended signal now has both of its endpoints near zero, which reduces the transients introduced. Call resample
and then add back the trend.
[ydetrend,ty] = resample(xdetrend,t,desiredFs,p,q,lpFilt); y = ydetrend + polyval(a,ty); plot(t,x,'.',ty,y) xlabel('Time') ylabel('RPM') legend('Original','Resampled (detrended, custom filter)','Location','best')
Summary
This example shows how to use resample
to convert uniformly and nonuniformly sampled signals to a fixed rate.
Further Reading
For more information on reconstructing nonuniformly spaced samples with custom splines, you can consult the Curve Fitting Toolbox™ documentation.