11.3. Numerical Differentiation¶
11.3.1. Euler Derivative¶
Computing a derivative numerically, is typically not difficult, but the accuracy of the calculation may be limited by the sampling rate of the data or by the limits of the computer to process very small numbers.
Calculus defines the derivative of with respect to as
For discretely sampled data, this becomes an approximation.
The variable represents the distance between the samples with respect to () and is proportional to the error, which may be acceptable for some applications, but not acceptable for other applications. This algorithm is called the forward Euler finite-difference derivative.
For sampled data values, the MATLAB function diff
returns the difference
between consecutive values, dy_dx = diff(y)/h;
. Note that the size of the
array returned by diff
is one element smaller than the array passed to
it.
To take the derivative of a function, first sample the data at intervals of
; and then use diff
as with pre-sampled data. The challenge is
to determine an appropriate value for . It should be small enough
to give good granularity. The evaluation of small enough depends entirely
on the data being evaluated. However, it should not be so small as to
require excessive computation or to cause excessive rounding errors from the
division by . As a rule of thumb, should not be much
smaller than . Some testing of different values of
may be required for some applications.
Try this example code and see how changing the value of h
,
affects the accuracy of the numerical derivative. Fig. 11.9
shows the plot when .
% File: deriv_cos.m
% Derivative example, Compute derivative of cos(x)
% sample step size, please experiment with h values
h = pi/40;
x = 0:h:2*pi;
y = cos(x);
dy_dx = diff(y)/h;
x1 = x(1:end-1); % note one less to match dy_dx
actual_dy = -sin(x1);
error = abs(dy_dx - actual_dy);
me = max(error);
ex = x1(error == me);
p1 = plot(x1, actual_dy, 'k', x1, dy_dx, 'r:');
title('Derivatives of cos(x)');
xticks(0:pi/2:2*pi);
xticklabels({'0','\pi/2','\pi','3\pi/2','2\pi'});
line([ex ex], [-1 1]);
text(ex+0.1, -0.4, 'Max error location');
legend(p1,{'analytic derivative','numerical derivative', },...
'Location', 'northwest');
disp(['Max error = ',num2str(me)]);
11.3.2. Spectral Derivative¶
The fast Fourier transform (FFT) provides a more accurate numerical method for estimating a derivative. The Fourier series, Fourier transform, and the inverse Fourier transform are algorithms proposed in 1807 by French mathematician Jean Baptiste Joseph Fourier (1768-1830) to characterize the frequencies present in continuous functions or signals. Later, the discrete Fourier transform (DFT) was used with sampled signals; however, the DFT can be rather slow for large data sets (). Then in 1965, James W. Cooley (IBM) and John W. Tukey (Princeton) developed the fast Fourier transform (FFT) algorithm that has run-time complexity of . The improved performance of the FFT stems from taking advantage of the symmetry found in the complex, orthogonal basis functions (). I will resist the temptation to go into a detailed description of the Fourier transform and the FFT. Many other resources cover that. For a fairly simple explanation, see my Machine Vision Study Guide, which emphasis the 2-D FFT used with images. A more rigorous, but still understandable coverage can be found in [BRUNTON19], pages 47 to 63.
The FFT is of interest to us here because of the simple relationship between the Fourier transform of a function and the Fourier transform of the function’s derivative. We can easily find the derivative in the frequency domain and then use the inverse FFT to put the derivative into its original domain.
Here, is the imaginary constant and is the frequency in radians per second for time domain data or just radians for spatial data. We can use for time domain data and for spatial domain data, where is the sample number in the range , is the number of data samples (usually a power of 2), is the sampling frequency (samples/second), and is the total length of the spacial domain data.
The following example is derived from Brunton’s book on data science and
engineering [BRUNTON19], pages 62 - 63, with a few modifications for clarity.
The example uses one dimensional, spatial domain data. The example shows how
the spectral derivative aligns with the analytic derivative. The FFT shows
frequency data as having both negative and positive frequencies, so our
needs to split the range of frequencies between the negative and
positive. For this example, we want to examine the function and derivative at
negative and positive values, so we can use our k
variable to build both
the spatial x
values and the frequency w
values. Both the FFT and
inverse FFT algorithms reorder the data, so we need to use the fftshift
function to align the frequency values with the frequency data.
%% SpectralDerivative.m
% Numerical derivative using the spectral derivative (FFT based)
% algorithm. Based off code from "Data Driven Science and
% Engineering" by Burnton and Kutz.
n = 128;
L = 15; % x data from -15 to 15
T = 2*L;
k = -n/2:(n/2 - 1);
x = T*k/n;
f = cos(x).*exp(-x.^2/25); % Function
df = -(sin(x).*exp(-x.^2/25) + (2/25)*x.*f); % Derivative
%% Derivative using FFT (spectral derivative)
fhat = fft(f);
w = pi*k/L; % radians, 2*pi*k/T = pi*k/L
omega = fftshift(w); % Re-order fft frequencies
i = complex(0, 1); % Define i just to be sure it is not used for
% something else, or could use 1i.
dfhat = i*omega.*fhat;
dfFFT = real(ifft(dfhat));
%% Plotting commands
figure, hold on
plot(x, f, 'b')
plot(x,df,'k','LineWidth',1.5)
plot(x,dfFFT,'r--','LineWidth',1.2)
legend('Function', 'True Derivative','FFT Derivative')
hold off
Here is an example of computing the spectral derivative using time domain data. Fig. 11.11 shows a plot of spectral time domain derivative, which aligns with the analytic derivative.
%% SpectralTimeDerivative.m
% Numerical derivative using the spectral derivative
% (FFT based) algorithm -- time domain data
n = 256;
fs = 8000; % samples/second
T = n/fs; % time span of samples (seconds)
k = -n/2:(n/2 - 1);
t = T*k/n; % time values
f1 = 200; % Two frequency components
f2 = 500;
f = 2*cos(2*pi*f1*t) + cos(2*pi*f2*t); % Function
df = -4*f1*pi*sin(2*pi*f1*t) - 2*f2*pi*sin(2*pi*f2*t); % Derivative
%% Derivative using FFT (spectral derivative)
fhat = fft(f);
w = 2*pi*fs*k/n; % radians / second
omega = fftshift(w); % Re-order fft frequencies
i = complex(0, 1); % Define i just to be sure it is not used for
% something else, or could use 1i.
dfhat = i*omega.*fhat;
dfFFT = real(ifft(dfhat));
%% Plotting commands
figure, plot(t, f, 'b') % derivatives too large for same plot
title('Function'), xlabel('seconds');
figure, hold on
plot(t, df,'k','LineWidth',1.5)
plot(t, dfFFT,'r--','LineWidth',1.2)
legend('True Derivative','FFT Derivative')
title('Derivatives'), xlabel('seconds');
hold off
%% Plot the power spectrum
pwr = abs(fhat).^2/n;
figure, plot(omega/(2*pi), pwr);
xlim([-800 800])
xlabel('Frequency (Hz)'), ylabel('Power'), title('Power Spectrum')