为什么 Python 的数值微分会改变正弦波的原始信号幅度?
Why does numerical differentiation with Python changes original signal amplitude for sine wave?
我用不同的方法计算了振幅为 1 的正弦波的数值导数。虽然相位看起来没问题,但当我期望原始信号的振幅相同 (~1) 时,我得到的导数信号振幅为 ~6。如果能帮助我理解为什么会这样,我将不胜感激。
这是我的代码和一个带有缩放和未缩放的导数值的图:
# -*- coding: utf-8 -*-
from __future__ import division
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
import matplotlib.pyplot as plt
from scipy.interpolate import splrep, splder, splev
## Useful Links
##
##
## ##
x = np.linspace(0,1,361)
# Create sin wave values
sin = np.sin(np.radians(np.linspace(0,361,361)))
# Create cosine wave values
cos = np.cos(np.radians(np.linspace(0,361,361)))
# Create scale factor for derivative values
scale = 6
## Method 1
# Get a function that evaluates the linear spline at any x
f = InterpolatedUnivariateSpline(x, sin, k=3)
# Get a function that evaluates the derivative of the linear spline at any x
dfdx = f.derivative()
# Evaluate the derivative dydx at each x location...
dydx_1_no_scaled = dfdx(x)
dydx_1_scaled = dfdx(x)/scale
## Method 2
# Calculate time step
dx = x[1] - x[0]
# Gradient method : central differences
dydx_2_no_scaled = (np.gradient(sin, dx))
dydx_2_scaled = (np.gradient(sin, dx))/6
## Method 3
# Approximations of derivatives
dydx_3_no_scaled = (np.diff(sin) / np.diff(x))
dydx_3_scaled = (np.diff(sin) / np.diff(x))/6
# Method 4 : Spline
time = np.linspace(0,1,361)
# Calculate signal spline func 'tck'
func = splrep(time, sin, s=0, k=3)
# Calculate derivative spline func 'tck'
der_func = splder(func, n=1)
# Calculate derivative values
dydx_4_no_scaled = splev(x, der_func, der=0, ext=0 )
dydx_4_scaled = splev(x, der_func, der=0, ext=0 )/6
plt.plot(sin)
plt.plot(cos)
plt.plot(dydx_1_no_scaled)
plt.plot(dydx_1_scaled)
plt.plot(dydx_2_no_scaled)
plt.plot(dydx_2_scaled)
plt.plot(dydx_3_no_scaled)
plt.plot(dydx_3_scaled)
plt.plot(dydx_4_no_scaled)
plt.plot(dydx_4_scaled)
plt.axvline(90)
plt.axvline(180)
plt.axvline(270)
plt.title('Sine Wave and respective derivative with 4 different methods')
plt.legend(['sin',
'cos',
'dydx_1_no_scaled', 'dydx_1_scaled',
'dydx_2_no_scaled', 'dydx_2_scaled',
'dydx_3_no_scaled', 'dydx_3_scaled',
'dydx_4_no_scaled', 'dydx_4_scaled'])
plt.show()
感谢您的帮助。
伊沃
数组sin
包含一个完整周期的正弦函数,对应的x
值范围是0到1。所以你计算出的函数是sin(2*pi*x)
。因此导数是2*pi*cos(2*pi*x)
。 (注意 ~6 是 ~2π。)
这是一个脚本,它使用 derivative()
方法来创建导数的插值器插值正弦函数。插值器在区间 [0, 2π] 上创建,这是 sin(x).
的一个周期
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
import matplotlib.pyplot as plt
num_samples = 250
x = np.linspace(0, 2*np.pi, num_samples)
y = np.sin(x)
f = InterpolatedUnivariateSpline(x, y, k=3)
dfdx = f.derivative()
print(np.max(np.abs(np.cos(x) - dfdx(x))))
plt.plot(x, dfdx(x), '--', label='dfdx(x)', linewidth=1)
plt.plot(x, np.cos(x), label='cos(x)', linewidth=4, alpha=0.25)
plt.legend(loc='lower left')
plt.xlabel('x')
plt.show()
程序打印 7.05390776901e-08
并生成以下图:
我用不同的方法计算了振幅为 1 的正弦波的数值导数。虽然相位看起来没问题,但当我期望原始信号的振幅相同 (~1) 时,我得到的导数信号振幅为 ~6。如果能帮助我理解为什么会这样,我将不胜感激。 这是我的代码和一个带有缩放和未缩放的导数值的图:
# -*- coding: utf-8 -*-
from __future__ import division
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
import matplotlib.pyplot as plt
from scipy.interpolate import splrep, splder, splev
## Useful Links
##
##
## ##
x = np.linspace(0,1,361)
# Create sin wave values
sin = np.sin(np.radians(np.linspace(0,361,361)))
# Create cosine wave values
cos = np.cos(np.radians(np.linspace(0,361,361)))
# Create scale factor for derivative values
scale = 6
## Method 1
# Get a function that evaluates the linear spline at any x
f = InterpolatedUnivariateSpline(x, sin, k=3)
# Get a function that evaluates the derivative of the linear spline at any x
dfdx = f.derivative()
# Evaluate the derivative dydx at each x location...
dydx_1_no_scaled = dfdx(x)
dydx_1_scaled = dfdx(x)/scale
## Method 2
# Calculate time step
dx = x[1] - x[0]
# Gradient method : central differences
dydx_2_no_scaled = (np.gradient(sin, dx))
dydx_2_scaled = (np.gradient(sin, dx))/6
## Method 3
# Approximations of derivatives
dydx_3_no_scaled = (np.diff(sin) / np.diff(x))
dydx_3_scaled = (np.diff(sin) / np.diff(x))/6
# Method 4 : Spline
time = np.linspace(0,1,361)
# Calculate signal spline func 'tck'
func = splrep(time, sin, s=0, k=3)
# Calculate derivative spline func 'tck'
der_func = splder(func, n=1)
# Calculate derivative values
dydx_4_no_scaled = splev(x, der_func, der=0, ext=0 )
dydx_4_scaled = splev(x, der_func, der=0, ext=0 )/6
plt.plot(sin)
plt.plot(cos)
plt.plot(dydx_1_no_scaled)
plt.plot(dydx_1_scaled)
plt.plot(dydx_2_no_scaled)
plt.plot(dydx_2_scaled)
plt.plot(dydx_3_no_scaled)
plt.plot(dydx_3_scaled)
plt.plot(dydx_4_no_scaled)
plt.plot(dydx_4_scaled)
plt.axvline(90)
plt.axvline(180)
plt.axvline(270)
plt.title('Sine Wave and respective derivative with 4 different methods')
plt.legend(['sin',
'cos',
'dydx_1_no_scaled', 'dydx_1_scaled',
'dydx_2_no_scaled', 'dydx_2_scaled',
'dydx_3_no_scaled', 'dydx_3_scaled',
'dydx_4_no_scaled', 'dydx_4_scaled'])
plt.show()
感谢您的帮助。 伊沃
数组sin
包含一个完整周期的正弦函数,对应的x
值范围是0到1。所以你计算出的函数是sin(2*pi*x)
。因此导数是2*pi*cos(2*pi*x)
。 (注意 ~6 是 ~2π。)
这是一个脚本,它使用 derivative()
方法来创建导数的插值器插值正弦函数。插值器在区间 [0, 2π] 上创建,这是 sin(x).
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
import matplotlib.pyplot as plt
num_samples = 250
x = np.linspace(0, 2*np.pi, num_samples)
y = np.sin(x)
f = InterpolatedUnivariateSpline(x, y, k=3)
dfdx = f.derivative()
print(np.max(np.abs(np.cos(x) - dfdx(x))))
plt.plot(x, dfdx(x), '--', label='dfdx(x)', linewidth=1)
plt.plot(x, np.cos(x), label='cos(x)', linewidth=4, alpha=0.25)
plt.legend(loc='lower left')
plt.xlabel('x')
plt.show()
程序打印 7.05390776901e-08
并生成以下图: