A quick "fix" would be to remove S
from the ParametricNDSolveValue
command:
Clear[knn, kf, knf, a];ttime = 10.253905;knf = 0.4;a = 2.36;model = ParametricNDSolveValue[{S1'[t] == (-kf*S1[t] - knn*S1[t]), NN'[t] == (knn*S1[t] - knf*NN[t]), S1[0] == 1, NN[0] == 0}, NN, {t, 0, ttime}, {kf, knn}];fit = FindFit[data, model[kf, knn][t], {{kf, 1.5}, {knn, 2}}, t](* {kf -> -1.17998, knn -> 4.35971} *)Plot[model[kf, knn][t] /. fit, {t, 0, ttime}, Epilog -> {Red, Point[data]}]
Image may be NSFW.
Clik here to view.
A better fix would be to directly use S
instead of NN
, incorporate the estimation of a
, and use NonlinearModelFit
:
a =.;model2 = ParametricNDSolveValue[{S1'[t] == (-kf*S1[t] - knn*S1[t]), S'[t] == a (knn*S1[t] - knf S[t]/a), S1[0] == 1, S[0] == 0}, S, {t, 0, ttime}, {a, kf, knn}];fit2 = NonlinearModelFit[data, model2[a, kf, knn][t], {{a, 1}, {kf, -1.5}, {knn, 4.4}}, t];fit2["BestFitParameters"](* {a -> 1.0003133640741626, kf -> -1.1786150346863764, knn -> 4.3583459462046354} *)Plot[model2[a, kf, knn][t] /. fit2["BestFitParameters"], {t, 0, ttime}, Epilog -> {Red, Point[data]}]
Image may be NSFW.
Clik here to view.
With NonlinearModelFit
you can get measure of precision for the estimated parameters (standard errors, confidence limits, correlations among parameters, etc.) and an assortment of model checking features. One essential feature is a look at the residuals (as you are assuming a particular error distribution):
ListPlot[Transpose[{fit2["PredictedResponse"], fit2["FitResiduals"]}], Frame -> True, FrameLabel -> {"Predicted", "Residual"}]
Image may be NSFW.
Clik here to view.
One can see a definite pattern remaining suggesting that more is going on that what the current model can describe. Also there appears to be a single data point that needs checking out.