Search code examples
pythonpython-3.xscipyscientific-computingidl-programming-language

scipy curve_fit fails when fitting to curve with large values


I am trying to fit some horizontal wind data to a cosine curve in order to estimate the direction and speed of winds at various heights (Velocity Azimuth Display), however it appears that whenever I attempt to do so with values > ~1, the curve appears way too flat and the output of the fit is lower than expected.

import numpy as np
import scipy.optimize as sc

azimuth = np.full((8), 60) #All values = 60 deg.
velocity = [5.6261001,6.6962662,3.9316666,-0.88413334,-5.4323335,-6.5153003,-3.2538002,1.0269333]
#Function that defines curve that data will be fitted to
def cos_Wave(x,a, b, c):
    return a * np.cos(x-b) + c

azimuthData = np.deg2rad(azimuth)
coeffs, matcov = sc.curve_fit(cos_Wave, azimuthData, velocity, p0 = (1,0,0)

plt.scatter(azimuthData, velocity)
plt.plot(azimuthData, cos_Wave(azimuthData, *coeffs))
plt.show()
print(coeffs)

With the coeffs output being:[ 1., 0., 0.13705066] and plot attached:

Python CurveFit

I have performed a similar curvefit using IDL's builtin curvefit function, and received more realistic values yielding [ 7.0348234, 0.59962606, 0.079354301] and providing a proper fit. Is there any reason why this is the case? I am assuming that it likely has something to do with the initial estimate (P0), however, utilizing an initial initial estimate in the IDL implementation still provides much more reasonable results.


Solution

  • You need to fix a few things:

    import numpy as np
    import scipy.optimize as sc
    import matplotlib.pyplot as plt
    
    azimuth = np.linspace(0, 360, 8)  # deg values from 0 to 360
    velocity = [5.6261001, 6.6962662, 3.9316666, -0.88413334, -5.4323335,
                -6.5153003, -3.2538002, 1.0269333]
    
    
    def cos_Wave(x, a, b, c):
        """Function that defines curve that data will be fitted to"""
        return a * np.cos(x-b) + c
    
    
    azimuthData = np.deg2rad(azimuth)
    coeffs, matcov = sc.curve_fit(cos_Wave, azimuthData, velocity, p0=[1, 0, 0])
    
    plt.scatter(azimuthData, velocity)
    nx = np.linspace(0, 2 * np.pi, 100)
    plt.plot(nx, cos_Wave(nx, *coeffs))
    plt.savefig("plot.png")
    print(coeffs)
    

    [ 6.63878549 1.03148322 -0.27674095]

    enter image description here