具有固定峰值的抛物线拟合
Parabolic fit with fixed peak
我有一组数据,想对其进行抛物线拟合。这已经适用于 numpy 的 polyfit 函数,如下所示:
fit = np.polyfit(X, y, 2)
formula = np.poly1d(fit)
现在我希望抛物线的峰值在一个固定的 x 值处,并且仍然尽可能地用这个固定的峰值进行拟合。有办法实现吗?
根据我的数据我知道抛物线总是向下开口。
我认为这是一个相当困难的问题,因为二阶多项式 (ax^2 + bx + c) 的峰值的 x 坐标总是位于x = -b/2a.
您可以做的一件事是删除 b 项并将其偏移到拟合多项式时所需的峰值 x 值,如下面的代码所示。请注意,我使用 scipy.optimize.curve_fit
来适应自定义函数 func
.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# generating a parabola with noise
np.random.seed(42)
x = np.linspace(-10, 10, 100)
y = 10 -(x-2)**2 + np.random.normal(0, 5, x.shape)
# function to fit
def func(x, a, c):
return a*x**2 + c
# desired x peak value
x_peak = 2
popt, pcov = curve_fit(func, x - x_peak, y)
y_fit = func(x - x_peak, *popt)
# plotting
plt.plot(x, y, 'k.')
plt.plot(x, y_fit)
plt.axvline(x_peak)
plt.show()
输出图像:
在你的抛物线上固定一个点可以简化问题,因为你现在可以根据常数稍微重写你的方程式:
y = A(x - B)**2 + C
给定原始无约束拟合中的系数 a
、b
、c
,您有关系
a = A
b = -2AB
c = AB**2 + C
唯一的区别是,由于B
是一个常数,而方程中没有x - B
项,因此您需要自己设置最小二乘问题。给定数组 x
、y
和常量 B
,问题如下所示:
m = np.stack((x - B, np.ones_like(x)), axis=-1)
(A, C), *_ = np.linalg.lstsq(m, y, rcond=None)
然后您可以从上述 a
、b
、c
的公式中提取正态系数。
这是一个完整的示例,就像另一个答案中的示例一样:
B = 2
np.random.seed(42)
x = np.linspace(-10, 10, 100)
y = 10 -(x - B)**2 + np.random.normal(0, 5, x.shape)
m = np.stack(((x - B)**2, np.ones_like(x)), axis=-1)
(A, C), *_ = np.linalg.lstsq(m, y, rcond=None)
a = A
b = -2 * A * B
c = A * B**2 + C
y_fit = a * x**2 + b * x + c
您可以完全删除 a
、b
、c
并执行
y_fit = A * (x - B)**2 + C
结果是一样的。
plt.plot(x, y, 'k.')
plt.plot(x, y_fit)
如果没有峰位置条件,要拟合的函数将是:
y = a x^2 + b x + c
在 x=p 处的峰位置条件下,给定 p :
-b/(2a)=p
b=-2个p
y = a x^2 -2 p x + c
y = a (x^2 - 2 p x) +c
知道 p ,变量的一个变化:
X = x^2 -2 p x
因此,首先根据数据 (x,y) 计算新数据 (X,y)
然后通过线性回归计算出 a 和 c
y = a X + c
我有一组数据,想对其进行抛物线拟合。这已经适用于 numpy 的 polyfit 函数,如下所示:
fit = np.polyfit(X, y, 2)
formula = np.poly1d(fit)
现在我希望抛物线的峰值在一个固定的 x 值处,并且仍然尽可能地用这个固定的峰值进行拟合。有办法实现吗?
根据我的数据我知道抛物线总是向下开口。
我认为这是一个相当困难的问题,因为二阶多项式 (ax^2 + bx + c) 的峰值的 x 坐标总是位于x = -b/2a.
您可以做的一件事是删除 b 项并将其偏移到拟合多项式时所需的峰值 x 值,如下面的代码所示。请注意,我使用 scipy.optimize.curve_fit
来适应自定义函数 func
.
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# generating a parabola with noise
np.random.seed(42)
x = np.linspace(-10, 10, 100)
y = 10 -(x-2)**2 + np.random.normal(0, 5, x.shape)
# function to fit
def func(x, a, c):
return a*x**2 + c
# desired x peak value
x_peak = 2
popt, pcov = curve_fit(func, x - x_peak, y)
y_fit = func(x - x_peak, *popt)
# plotting
plt.plot(x, y, 'k.')
plt.plot(x, y_fit)
plt.axvline(x_peak)
plt.show()
输出图像:
在你的抛物线上固定一个点可以简化问题,因为你现在可以根据常数稍微重写你的方程式:
y = A(x - B)**2 + C
给定原始无约束拟合中的系数 a
、b
、c
,您有关系
a = A
b = -2AB
c = AB**2 + C
唯一的区别是,由于B
是一个常数,而方程中没有x - B
项,因此您需要自己设置最小二乘问题。给定数组 x
、y
和常量 B
,问题如下所示:
m = np.stack((x - B, np.ones_like(x)), axis=-1)
(A, C), *_ = np.linalg.lstsq(m, y, rcond=None)
然后您可以从上述 a
、b
、c
的公式中提取正态系数。
这是一个完整的示例,就像另一个答案中的示例一样:
B = 2
np.random.seed(42)
x = np.linspace(-10, 10, 100)
y = 10 -(x - B)**2 + np.random.normal(0, 5, x.shape)
m = np.stack(((x - B)**2, np.ones_like(x)), axis=-1)
(A, C), *_ = np.linalg.lstsq(m, y, rcond=None)
a = A
b = -2 * A * B
c = A * B**2 + C
y_fit = a * x**2 + b * x + c
您可以完全删除 a
、b
、c
并执行
y_fit = A * (x - B)**2 + C
结果是一样的。
plt.plot(x, y, 'k.')
plt.plot(x, y_fit)
如果没有峰位置条件,要拟合的函数将是:
y = a x^2 + b x + c
在 x=p 处的峰位置条件下,给定 p :
-b/(2a)=p
b=-2个p
y = a x^2 -2 p x + c
y = a (x^2 - 2 p x) +c
知道 p ,变量的一个变化:
X = x^2 -2 p x
因此,首先根据数据 (x,y) 计算新数据 (X,y)
然后通过线性回归计算出 a 和 c
y = a X + c