There is no built-in way to accomplish what you want with NonlinearModelFit
, or with the other fitting functions, unfortunately. Of course, you could write your own target function and NMinimize that, as belisarius has mentioned already in his answer. This is very general and not particularly difficult to do, but it does not give you access to the wealth of built-in fit description parameters that are accessible through NonlinearModelFit
. Again, you could recalculate those manually, but it would be useful to be able to leverage the existing functionality instead.
In order to "trick" NonlinearModelFit
into fitting your multivariate model, you will want to build an object function that includes both models and can "switch between them", based on a dummy selector variable that you will introduce in your data set and treat as an independent variable.
Let's go through a simple example. I generated some noisy data as a function of a common $x$ range which is the actual independent variable in your physical model. The two functions I used to generate the dependent variables are $y_1=x^2-5x+3$ and $y_2=0.1\ x^3-3$. I then added some random noise to the $y$ variables just to make this slightly more realistic. Here is the data set:
originaldata = {{-10, 168, -83}, {-9, 150.1, -86.9}, {-8, 129.6, -36.2}, {-7, 101.5, -34.3}, {-6, 74.8, -14.6}, {-5, 52.5, -32.5}, {-4, 48.6, -12.4}, {-3, 21.1, -23.7}, {-2, 22, -7.8}, {-1, 15.3, 5.9}, {0, 5, 8}, {1, -3.9, -7.9}, {2, -11.4, -7.2}, {3, -11.5, -11.3}, {4, 10.8, 22.4}, {5, 4.5, 8.5}, {6, 14.6, 29.6}, {7, 28.1, 31.3}, {8, 33, 31.2}, {9, 61.3, 68.9}, {10, 76, 96}};
ListPlot[originaldata[[All, {1, #}]] & /@ {2, 3}, PlotRange -> All]
You will have to reorganize this data set so that each point has the following form: {xValue, datasetIndentifier, yValue}
, where we will use the numbers $1$ or $2$ as dataset indentifiers.
Transpose@originaldata;
Insert[%[[{1, #}]], ConstantArray[# - 1, Length[originaldata]], 2] & /@ {2, 3};
reorganizeddata = Flatten[Transpose /@ %, 1]
{{-10, 1, 153}, {-9, 1, 131}, {-8, 1, 107}, {-7, 1, 80}, {-6, 1, 59}, {-5, 1, 59}, {-4, 1, 31}, {-3, 1, 27}, {-2, 1, 21}, {-1, 1, 14}, {0, 1, 5}, {1, 1, 9}, {2, 1, -9}, {3, 1, -10}, {4, 1, 7}, {5, 1, 2}, {6, 1, 8}, {7, 1, 25}, {8, 1, 26}, {9, 1, 33}, {10, 1, 45}, {-10, 2, 139.36}, {-9, 2, 79.6883}, {-8, 2, 0.47189}, {-7, 2, -35.8288}, {-6, 2, -31.6333}, {-5, 2, -47.4649}, {-4, 2, -15.9864}, {-3, 2, 3.2233}, {-2, 2, -4.73885}, {-1, 2, -3.77884}, {0, 2, -20}, {1, 2, -0.221163}, {2, 2, -13.2612}, {3, 2, 13.7767}, {4, 2, 24.9864}, {5, 2, 52.4649}, {6, 2, 54.6333}, {7, 2, 12.8288}, {8, 2, -6.47189}, {9, 2, -80.6883}, {10, 2, -154.36}}
Now let's create an appropriate model function.
Clear[modelfunction]
modelfunction[indepvar_?NumericQ, datasetselector_?NumericQ, p11_?NumericQ, p12_?NumericQ, p13_?NumericQ, p21_?NumericQ, p22_?NumericQ] :=
Piecewise[{
{p11 indepvar^2 + p12 indepvar + p13,
datasetselector == 1},
{p21 indepvar^3 + p22,
datasetselector == 2}
}]
... and use it with NonlinearModelFit
:
nlm = NonlinearModelFit[
reorganizeddata,
modelfunction[x, selector, a, b, c, d, e],
{a, b, c, d, e},
{x, selector}
]
We can then very conveniently extract any of the fit descriptors available through NonlinearModelFit
:
nlm["ParameterTable"]
nlm["RSquared"]
Of course you can also plot the experimental points and the fit:
Plot[
nlm["BestFit"] /. selector -> # & /@ {1, 2}, {x, -10, 10},
Epilog -> {PointSize[0.015], Gray, Point[reorganizeddata[[All, {1, 3}]]]},
Evaluated -> True
]