I have datapoints that give information about the evolution of the temperature of an object over time. Following are these datapoints plotted
My goal is to fit a function as precise as possible to find the evolution of the temperature in the future (where i have no data) and find the "temperature limit" (the max temperature)
Now I tried to fit the function with a logarithm function,
def func_log(x, a, b, c, d):
return a * np.log(b * (x+c)) + d
# ...
expected_coefs_log = [1, 0.3, 1, 1]
popt, pcov = curve_fit(func_log, self.time, self.temp, expected_coefs_log)
but as you can see on the second image, the result is not precise enough.Is it possible to "rotate" the fitted curve to the right? Seems like this function could fit, if only I could rotate it a little bit...
If this is not possible, do you have an idea how I could solve this problem?
The correct approach obviously depends on your data and your model. However, one way to force a curve into a certain shape is to utilize weights during the fitting procedure:
import numpy as np
from scipy.optimize import curve_fit
from matplotlib import pyplot as plt
#simulate the data
def func_exp(x, a, b, c, d):
return a * (1 - b* np.exp(-c*x)) + d
np.random.seed(123456789)
n=400
time_real = np.linspace(0, 5000, n)
temp_real = func_exp(time_real, 21, 0.7, 0.001, 63) + np.random.random(n)
n_measured = int(n*0.5)
time_measured = time_real[:n_measured]
temp_measured = temp_real[:n_measured]
#curve fitting a logarithmic function on the data
def func_log(x, a, b, c, d):
return a * np.log(b * (x+c)) + d
#without weights
expected_coefs_log = [3, 1, 1, 1]
popt_noweight, pcov = curve_fit(func_log, time_measured, temp_measured, expected_coefs_log)
print(popt_noweight)
#artificial weights emphasizing points at a later time point
sigma_coefs_log = np.linspace(5, 0.01, len(time_measured))
popt_weight, pcov = curve_fit(func_log, time_measured, temp_measured, p0=expected_coefs_log, sigma=sigma_coefs_log)
print(popt_weight)
#graphic representation
plt.scatter(time_real, temp_real, c="orange", marker=".", label="expected data")
plt.scatter(time_measured, temp_measured, color="red", marker=".", label="measured data")
plt.plot(time_real, func_log(time_real, *popt_noweight), color="blue", label="fit, no weight")
plt.plot(time_real, func_log(time_real, *popt_weight), color="green", label="fit, weight")
plt.legend()
plt.show()
However, if you expect a plateau (it is not explained in your question why you think the "wanted function" should be correct), a logarithmic model may just the wrong function type, as we can see by the tradeoff in the initial part that is now less adapted to the data.