问题
I am trying to compute the derivative of some data and I was trying to compare the output of a finite difference and a spectral method output. But the results are very different and I can't figure out exactly why.
Consider the example code below
import numpy as np
from scipy import fftpack as sp
from matplotlib import pyplot as plt
x = np.arange(-100,100,1)
y = np.sin(x)
plt.plot(np.diff(y)/np.diff(x))
plt.plot(sp.diff(y))
plt.show()
This outputs the following result
The orange output being the fftpack
output. Nevermind the subtleties, this is just for the sake of an example.
So, why are they so different? Shouldn't they be (approximately) the same?
I'm pretty sure that the different amplitudes can be corrected with fftpack.diff
's period keyword, but I can't figure which is the correct period (I thought it should be period=1
but that doesn't work).
Furthermore, how can I have my own spectral differentiation using numpy?
回答1:
The function scipy.fftpack.diff computes the derivative, but it assumes that the input is periodic. The period
argument gives the period (i.e. the total length of the x
interval) of the input sequence.
In your case, this is len(x)*dx
where dx = x[1] - x[0]
.
Here's some code that plots the simple (centered) finite difference (in blue) and the result of diff
using the period
argument (in red). The variables x
and y
are the same as those used in your code:
In [115]: plt.plot(0.5*(x[1:]+x[:-1]), np.diff(y)/np.diff(x), 'b')
Out[115]: [<matplotlib.lines.Line2D at 0x1188d01d0>]
In [116]: plt.plot(x, sp.diff(y, period=len(x)*(x[1]-x[0])), 'r')
Out[116]: [<matplotlib.lines.Line2D at 0x1188fc9d0>]
In [117]: plt.xlabel('x')
Out[117]: <matplotlib.text.Text at 0x1157425d0>
Note that if your input is not actually periodic, the derivative computed by diff
will be inaccurate near the ends of the interval.
Here's another example, using a shorter sequence that contains just one full period of a sine function in the interval [0, 1]:
In [149]: x = np.linspace(0, 1, 20, endpoint=False)
In [150]: y = np.sin(2*np.pi*x)
In [151]: plt.plot(0.5*(x[1:]+x[:-1]), np.diff(y)/np.diff(x), 'b')
Out[151]: [<matplotlib.lines.Line2D at 0x119872d90>]
In [152]: plt.plot(x, sp.diff(y, period=len(x)*(x[1]-x[0])), 'r')
Out[152]: [<matplotlib.lines.Line2D at 0x119c49090>]
In [153]: plt.xlabel('x')
Out[153]: <matplotlib.text.Text at 0x1197823d0>
回答2:
1 rad is a rather coarse stride for the difference approximation, and you should want integer number of periods in the dataset
x = np.arange(-200,200,1)
y = np.sin(np.pi/50*x)
plt.plot(np.diff(y)/np.diff(x))
plt.plot(sp.diff(y,order=1, period=400))
matches pretty well - but I don't know the the exact rational for the period/normalization in the fft routine
来源:https://stackoverflow.com/questions/42197460/numpy-diff-and-scipy-fftpack-diff-giving-different-results-when-differentiat