Dopasowywanie dwóch różnych równań do funkcji (dopasowanie_krzywej)

Nov 23 2020

Mam problem: mam dwa różne równania, jedno to równanie liniowe, drugie to równanie wykładnicze. Jednak nie oba równania powinny być ważne w tym samym czasie, co oznacza, że ​​istnieją dwa różne reżimy.

Equation 1 (x < a): E*x
Equation 2 (x >=a): a+b*x+c*(1-np.exp(-d*np.array(x)))

Oznacza to, że pierwsza część danych powinna być dopasowana do równania liniowego, a reszta powinna być dopasowana do wcześniej wspomnianego równania 2.

Dane, które próbuję dopasować, wyglądają następująco (dodałem również kilka przykładowych danych, jeśli ludzie chcą spróbować):

Próbowałem już kilku rzeczy, od zdefiniowania tylko jednej funkcji dopasowania z funkcją ciężką:

def fit_fun(x,a,b,c,d,E):
    
    funktion1=E*np.array(x)
    
    funktion2=a+b*x+c*(1-np.exp(-d*np.array(x)))
           
    return np.heaviside(x+a,0)*funktion2+(1-np.heaviside(x+a,0))*funktion1

definiowanie funkcji odcinkowej:

def fit_fun(x,a,b,c,d,E):
    return np.piecewise(x, [x <= a, x > a], [lambda x: E*np.array(x), lambda x: a+b*x+c*(1-np.exp(-d*np.array(x)))])

na koniec (co niestety daje mi jakiś błąd funkcji formularza?):

def plast_fun(x,a,b,c,d,E):
   
    out = E*x
    out [np.where(x >= a)] = a+b*x+c*(1-np.exp(-d+x))
    
    return out

Nie zrozum mnie źle, dostaję „pewne” ataki, ale wydają się one albo przyjmować jedno, albo drugie równanie i tak naprawdę nie używają obu. Próbowałem też użyć kilku ograniczeń i domysłów, ale to się nigdy nie zmienia.

Każdy wkład będzie mile widziany!

Dane:

0.000000     -1.570670 
0.000434     83.292677 
0.000867     108.909402 
0.001301     124.121676 
0.001734     138.187659 
0.002168     151.278839 
0.002601     163.160478 
0.003035     174.255626 
0.003468     185.035092 
0.003902     195.629820 
0.004336     205.887161 
0.004769     215.611995 
0.005203     224.752083 
0.005636     233.436680 
0.006070     241.897851 
0.006503     250.352697 
0.006937     258.915168 
0.007370     267.569337 
0.007804     276.199005 
0.008237     284.646778 
0.008671     292.772349 
0.009105     300.489611 
0.009538     307.776858 
0.009972     314.666291 
0.010405     321.224211 
0.010839     327.531594 
0.011272     333.669261 
0.011706     339.706420 
0.012139     345.689265 
0.012573     351.628362 
0.013007     357.488150 
0.013440     363.185771 
0.013874     368.606298 
0.014307     373.635696 
0.014741     378.203192 
0.015174     382.315634 
0.015608     386.064126 
0.016041     389.592120 
0.016475     393.033854 
0.016908     396.454226 
0.017342     399.831519 
0.017776     403.107084 
0.018209     406.277016 
0.018643     409.441119 
0.019076     412.710982 
0.019510     415.987331 
0.019943     418.873140 
0.020377     421.178098 
0.020810     423.756827 

Do tej pory znalazłem te dwa pytania, ale nie mogłem tego rozgryźć: Dopasowanie dwóch różnych funkcji z granicą jako parametrem dopasowania Dopasuj krzywą dla danych składających się z dwóch różnych reżimów

Odpowiedzi

2 FlavioMoraes Nov 23 2020 at 23:35

Podejrzewam, że popełniasz błąd w drugim równaniu, w którym to robisz a+b*x+c*(1-np.exp(-d+x)). gdzie ajest wartością xmiejsca zmiany z jednej krzywej na drugą. Myślę, że yzamiast tego należy użyć wartości, która jest a*E. Bardzo ważne jest również zdefiniowanie początkowych parametrów dopasowania. Uruchomiłem następujący kod z twoimi danymi w pliku .txt i dopasowanie wydaje się całkiem dobre, jak widać poniżej:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import optimize, stats

def fit_fun(x,a,b,c,d,E):
    return np.piecewise(x, [x <= a, x > a], [lambda x: E*x, lambda x: a*E+b*x+c*(1-np.exp(-d*x))])

df = pd.read_csv('teste.txt', delimiter='\s+', header=None)
df.columns = ['x','y']

xdata = df['x']
ydata = df['y']

p0 = [0.001,1,1,1,100000]
popt, pcov = optimize.curve_fit(fit_fun, xdata.values, ydata.values, p0=p0, maxfev=10000, absolute_sigma=True, method='trf')
print(popt)

plt.plot(xdata, ydata,'*')
plt.plot(xdata, fit_fun(xdata.values, *popt), 'r')
plt.show()