【问题标题】:How to fit an inverse sawtooth function to a curve or a plot?如何将反锯齿函数拟合到曲线或绘图?
【发布时间】:2019-10-22 05:54:59
【问题描述】:

我有一个应该是锯齿波的情节。

我正在尝试将锯齿方程(如 wiki 中给出的)拟合到数据点,但我无法这样做。

n_step_list = [-500, -400, -300, -200, -100, 0, 100, 200, 300, 400, 500]
value_list =  [-24, 73, 55, 36, 18, 0, -18, 79, 61, 43, 24]

def f(x, A, fi):
    total_sum = 0
    i = 1
    while i < 151:
        total_sum += np.power(-1, i) * np.sin(2 * np.pi * i * fi * x) / i
        i += 1

    total_sum *= 2 * A / np.pi

    return total_sum

A, fi = curve_fit(f, n_step_list, value_list, (10000000000000, 28))[0]

但我得到了荒谬的结果。最初的猜测,我使用一个值 (-100, 18) 提供给 curve_fit 并尝试计算 A 和 fi 的值。任何帮助表示赞赏。

【问题讨论】:

    标签: python python-3.x scipy curve-fitting scipy-optimize


    【解决方案1】:

    这是一个不同的拟合器,使用 scipy 的锯齿波形发生器和 scipy 的差分进化遗传算法给出的初始参数估计。参数“width”特定于代码中引用的锯齿波发生器,确定波形是上升、下降还是对称的,根据 scipy 文档,范围从 0 到 1。

        import numpy, scipy, matplotlib
        import matplotlib.pyplot as plt
        from scipy.optimize import curve_fit
        from scipy.optimize import differential_evolution
        import warnings
        import scipy.signal
    
    
        n_step_list = [-500.0, -400.0, -300.0, -200.0, -100.0, 0.0, 100.0, 200.0, 300.0, 400.0, 500.0]
        value_list =  [-24.0, 73.0, 55.0, 36.0, 18.0, 0.0, -18.0, 79.0, 61.0, 43.0, 24.0]
    
        xData = numpy.array(n_step_list)
        yData = numpy.array(value_list)
    
    
        # width is from scipy docs at https://www.pydoc.io/pypi/scipy-1.0.1/autoapi/signal/waveforms/index.html#signal.waveforms.sawtooth
        def func(x, A, fi, offset, width):
            return A * scipy.signal.sawtooth(x / fi, width) + offset
    
    
        # function for genetic algorithm to minimize (sum of squared error)
        def sumOfSquaredError(parameterTuple):
            warnings.filterwarnings("ignore") # do not print warnings by genetic algorithm
            val = func(xData, *parameterTuple)
            return numpy.sum((yData - val) ** 2.0)
    
    
        def generate_Initial_Parameters():
            # min and max used for bounds
            maxX = max(xData)
            minX = min(xData)
            maxY = max(yData)
            minY = min(yData)
    
            minData = min(minY, minX)
            maxData = max(maxY, maxX)
    
            parameterBounds = []
            parameterBounds.append([minData, maxData]) # search bounds for A
            parameterBounds.append([minData, maxData]) # search bounds for fi
            parameterBounds.append([minData, maxData]) # search bounds for Offset
            parameterBounds.append([0, 1]) # search bounds for width, see https://www.pydoc.io/pypi/scipy-1.0.1/autoapi/signal/waveforms/index.html#signal.waveforms.sawtooth
    
            # "seed" the numpy random number generator for repeatable results
            result = differential_evolution(sumOfSquaredError, parameterBounds, seed=3)
            return result.x
    
        # by default, differential_evolution completes by calling curve_fit() using parameter bounds
        geneticParameters = generate_Initial_Parameters()
    
        # now call curve_fit without passing bounds from the genetic algorithm,
        # just in case the best fit parameters are aoutside those bounds
        fittedParameters, pcov = curve_fit(func, xData, yData, geneticParameters)
        print('Fitted parameters:', fittedParameters)
        print()
    
        modelPredictions = func(xData, *fittedParameters) 
    
        absError = modelPredictions - yData
    
        SE = numpy.square(absError) # squared errors
        MSE = numpy.mean(SE) # mean squared errors
        RMSE = numpy.sqrt(MSE) # Root Mean Squared Error, RMSE
        Rsquared = 1.0 - (numpy.var(absError) / numpy.var(yData))
    
        print()
        print('RMSE:', RMSE)
        print('R-squared:', Rsquared)
    
        print()
    
    
        ##########################################################
        # graphics output section
        def ModelAndScatterPlot(graphWidth, graphHeight):
            f = plt.figure(figsize=(graphWidth/100.0, graphHeight/100.0), dpi=100)
            axes = f.add_subplot(111)
    
            # first the raw data as a scatter plot
            axes.plot(xData, yData,  'D')
    
            # create data for the fitted equation plot
            xModel = numpy.linspace(min(xData), max(xData))
            yModel = func(xModel, *fittedParameters)
    
            # now the model as a line plot
            axes.plot(xModel, yModel)
    
            axes.set_xlabel('X Data') # X axis data label
            axes.set_ylabel('Y Data') # Y axis data label
    
            plt.show()
            plt.close('all') # clean up after using pyplot
    
        graphWidth = 800
        graphHeight = 600
        ModelAndScatterPlot(graphWidth, graphHeight)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-01
      相关资源
      最近更新 更多