绘制分段拟合非线性数据

时间:2015-12-04 13:53:11

标签: python numpy matplotlib scipy curve-fitting

我遇到与this previous StackOverflow question类似的问题。我有一个数据集,我想要拟合几个分段函数,然后绘制结果。

下面用红色绘制数据。

为了给出一些上下文,y值表示电机转动x度所需的毫秒数。我已将原始值上传到this Pastebin

我现在想以分段方式适应三个功能:

  • 适用于数据起点的多项式,其中电机正在加速到最大速度。
  • 达到最大速度时的线性拟合。
  • 多项式拟合,然后电机关闭,并减速。

到目前为止,我已尝试使用下面显示的代码执行两个线性函数的分段拟合。考虑到数据的样子,我期望看到从原点到约ms=550的数据后面有一个斜率,然后从那里看到一条平行于x轴的第二条线。

但是,这不是我得到的:

Data with fit

在我尝试使用三个函数执行分段拟合之前,我首先想了解为什么我得到这个情节而不是我所期待的。

所以我的问题是:

  1. 任何人都可以解释如何纠正我的代码以使其适合两个线性函数吗?
  2. 如何使用三个函数扩展我的代码以绘制分段拟合?
  3. 用于创建上图的代码如下:

    from pandas import *
    import matplotlib.pyplot as plt
    import numpy as np
    from scipy import optimize
    
    #Getting data using Pandas
    df = read_csv("test_data.csv")
    ms = df["ms"].values
    degrees = df["Degrees"].values
    
    #A piece wise function taken from the other stackoverflow
    def piecewise_linear(x, x0, y0, k1, k2):
        return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])
    
    #Setting linspace and making the fit
    x_new = np.linspace(ms[0], ms[-1])
    
    p , e = optimize.curve_fit(piecewise_linear, ms, degrees)
    
    
    #Plotting data and fit
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    
    ax.plot(x_new, piecewise_linear(x_new, *p), '.', df)
    ax.set_ylim([0, 450])
    ax.set_xlim([0, 800])
    

1 个答案:

答案 0 :(得分:3)

<强> 2。问题:你需要重新定义piecewise_linear,现在它有三个部分,你可以随意改变它们(我只是举了一个二度,一度和三度多项式的例子)。

#Piecewise function defining 2nd deg, 1st degree and 3rd degree exponentials
def piecewise_linear(x, x0, x1, y0, y1, k1, k2, k3, k4, k5, k6):
    return np.piecewise(x, [x < x0, x>= x0, x> x1], [lambda x:k1*x + k2*x**2, lambda x:k3*x + y0, lambda x: k4*x + k5*x**2 + k6*x**3 + y1])

<强> 1。问题:显然,为了使用curve_fit(),您需要转换为numpy数组。

#Setting linspace and making the fit, make sure to make you data numpy arrays
x_new = np.linspace(ms[0], ms[-1], dtype=float)
m = np.array(ms, dtype=float)
deg = np.array(degrees, dtype=float)
guess = np.array( [100, 500, -30, 350, -0.1, 0.0051, 1, -0.01, -0.01, -0.01], dtype=float)
p , e = optimize.curve_fit(piecewise_linear, m, deg)
#Plotting data and fit
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x_new, piecewise_linear(x_new, *p), '-', df)
ax.set_ylim([0, 450])
ax.set_xlim([0, 800])

作为旁注,我还为你的初始参数添加了一些有根据的猜测,这让你比让python随机选择更合适。

然后做

ax.plot(x_new, piecewise_linear(x_new, *p), '-', ms[::20], degrees[::20], 'o')

enter image description here