SciPy leastsq fit einer Sinus-Welle versagt
Ich versuche herauszufinden, was es ist, ich verstehe nicht hier.
Ich bin nach http://www.scipy.org/Cookbook/FittingData und versuchen, fit einer Sinus-Welle. Das eigentliche problem ist die Sat-magnetometer-Daten, wodurch eine schöne Sinuskurve auf einem sich drehenden Raumschiff. Ich erstellt ein dataset, dann versuche, es passt zum wiederherstellen der Eingänge.
Hier ist mein code:
import numpy as np
from scipy import optimize
from scipy.optimize import curve_fit, leastsq
import matplotlib.pyplot as plt
class Parameter:
def __init__(self, value):
self.value = value
def set(self, value):
self.value = value
def __call__(self):
return self.value
def fit(function, parameters, y, x = None):
def f(params):
i = 0
for p in parameters:
p.set(params[i])
i += 1
return y - function(x)
if x is None: x = np.arange(y.shape[0])
p = [param() for param in parameters]
return optimize.leastsq(f, p, full_output=True, ftol=1e-6, xtol=1e-6)
# generate a perfect data set (my real data have tiny error)
def mysine(x, a1, a2, a3):
return a1 * np.sin(a2 * x + a3)
xReal = np.arange(500)/10.
a1 = 200.
a2 = 2*np.pi/10.5 # omega, 10.5 is the period
a3 = np.deg2rad(10.) # 10 degree phase offset
yReal = mysine(xReal, a1, a2, a3)
# plot the real data
plt.figure(figsize=(15,5))
plt.plot(xReal, yReal, 'r', label='Real Values')
# giving initial parameters
amplitude = Parameter(175.)
frequency = Parameter(2*np.pi/8.)
phase = Parameter(0.0)
# define your function:
def f(x): return amplitude() * np.sin(frequency() * x + phase())
# fit! (given that data is an array with the data to fit)
out = fit(f, [amplitude, frequency, phase], yReal, xReal)
period = 2*np.pi/frequency()
print amplitude(), period, np.rad2deg(phase())
xx = np.linspace(0, np.max(xReal), 50)
plt.plot( xx, f(xx) , label='fit')
plt.legend(shadow=True, fancybox=True)
Macht dieses Grundstück:
Die wiederhergestellten fit-Parameter der [44.2434221897 8.094832581 -61.6204033699]
haben keine ähnlichkeit mit dem, was ich mit gestartet.
Irgendwelche Gedanken auf, was ich nicht verstehen oder falsch?
scipy.__version__
'0.10.1'
Bearbeiten:
Die Fixierung auf einen parameter, wurde vorgeschlagen. In dem obigen Beispiel die Festsetzung der amplitude zu np.histogram(yReal)[1][-1]
produziert immer noch inakzeptabel Ausgabe. Passend für: [175.0 8.31681375217 6.0]
Sollte ich versuchen, eine andere passende Methode? Vorschläge, welche?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist etwas code, der Umsetzung einiger Zhenya Ideen.
Es nutzt
vorstellen, die Haupt-Frequenz, mit der Daten, und
erraten der amplitude.
Erträge
Beachten Sie, dass durch die Verwendung der fft, die Vermutung für die Frequenz ist schon ziemlich nah an der endgültigen parameter ausgestattet.
Es scheint, dass Sie nicht brauchen, um fix einen der Parameter.
Indem die Frequenz erraten näher an dem tatsächlichen Wert
optimize.curve_fit
ist in der Lage zu konvergieren, um eine vernünftige Antwort.Von dem, was ich sehen kann, spielen ein bisschen mit
leastsq
(ohne ausgefallene Sachen aus dem Kochbuch, einfach direkte Aufrufe anleastsq
--- und übrigensfull_output=True
ist dein Freund hier), ist, dass es sehr schwer ist, passen alle drei von der amplitude, Frequenz und phase in einem Rutsch. Auf der anderen Seite, wenn ich fix die amplitude und passen die Frequenz und phase ist, funktioniert es; wenn ich fix die Frequenz und passen die amplitude und die phase, es funktioniert auch.Gibt es mehr als einen Weg hier heraus. Was wäre das einfachste --- wenn Sie sicher sind, dass Sie nur eine Sinus-Wellenform (und das ist leicht zu überprüfen mit der Fourier-Transformation), dann wissen Sie die Frequenz aus, nur der Abstand zwischen zwei aufeinander folgenden maxima des Signals. Dann passen die beiden verbleibenden Parameter.
Wenn das, was Sie haben, ist eine Mischung aus mehreren Obertönen, gut, wieder, Fourier-Transformation wird Ihnen sagen, dass.