Short Version: I have a parameterized function (the model) that returns a list of values. I have data that I want to fit this model to, optimizing those parameters, where the list position in the data corresponds to the list position in the model result that is returned by the function. How do I do this using NonlinearModelFit so that I can use the various statistical analyses present in the resulting FittedModel?
Full Version: I have experimental data for a uniform, discrete set of times t. I want to fit this data to a nonlinear model including convolution with a known instrument function. As I determined in a prior question, Convolve fails (Wolfram has indicated that there are machine underflow errors; they provided a workaround, but it is quite slow for my system), but ListConvolve on the same range of t works, and in fact is quite fast. Let's define the model, the instrument function, and some faux data so that we have something to work with:
F[t_, Finf_, A1_, k1_, A2_, k2_, t0_] = Finf - A1 - A2 +
UnitStep[t - t0]
(A1 + A2 - A1 E^(-k1 (t - t0)) - A2 E^(-k2 (t - t0)));
dn = {0.336025, 0.441503, 0.11445, 0.0549757, 0.0270152, 0.0132802,
0.00652836, 0.00320924, 0.00157762, 0.000775533, 0.00038124,
0.000187412, 0.000092129};
tlist = Range[0, 600, 3];
data = ListConvolve[dn, F[tlist, 4, 2, 0.3, 1.5, 0.03, 50], {1, 1},
0.5] + RandomVariate[NormalDistribution[0, 0.02], Length[tlist]];
Here is the instrument function (dn) vs. point number:
Here is the data:
ListPlot[{tlist, data} // Transpose, PlotRange -> Full]
Now I generate the model points at the experimental times. This is a function of the variable parameters I want to optimize, and involves a ListConvolve.
modelpoints[Finf_, A1_, k1_, A2_, k2_, t0_] =
ListConvolve[dn, F[tlist, Finf, A1, k1, A2, k2, t0], {1, 1},
Finf - A1 - A2];
Thus, modelpoints returns a list of modeled, convolved y-values at the same time points as the data. Picking parameters slightly different so that the fitting process has somewhere to go:
initGuess = {Finf -> 3.9, A1 -> 2.1, k1 -> 0.2, A2 -> 1.4, k2 -> 0.04,
t0 -> 51};
Show[ListPlot[{tlist, data} // Transpose, PlotRange -> Full],
ListLinePlot[{tlist, modelpoints[Finf, A1, k1, A2, k2, t0] /. initGuess}
// Transpose, PlotStyle -> Red, PlotRange -> Full]]
I can certainly go the manual route of calculating chi-squares and minimizing that value, as follows:
chiSq[Finf_, A1_, k1_, A2_, k2_, t0_] =
Total[(data - modelpoints[Finf, A1, k1, A2, k2, t0])^2];
guessRange = {#, 0.9 (# /. initGuess),
1.1 (# /. initGuess)} & /@ {Finf, A1, k1, A2, k2, t0};
NMinimize[chiSq[Finf, A1, k1, A2, k2, t0], guessRange]
(* {0.0860335, {Finf -> 3.99996, A1 -> 2.02402, k1 -> 0.311155,
A2 -> 1.47918, k2 -> 0.0300756, t0 -> 50.0683}} *)
But it would be wonderful if I could use NonlinearModelFit because of all of its built-in diagnostic functionality. However, I have been unable to find a way to use NonlinearModelFit in a case where the fitting form produces a list of points that should match a list of data points. Can anyone point me to a way to do this? The general idea would be something like:
NonlinearModelFit[data,modelpoints[Finf,A1,k1,A2,k2,t0][[i]],
{#,#/.initGuess}&/@{Finf, A1, k1, A2, k2, t0},i]
Here I am trying (in vain) to use i as the independent variable (of course, it needs to be restricted to positive integers). But this does not work. A comment in this question suggests that NonlinearModelFit can be used if the function is discrete, but doesn't provide any examples. Further it seems that the NominalVariables option is not available for NonlinearModelFit. I have also tried a workaround by turning the model into an InterpolatingFunction, but not only is that really slow, it also gives errors.