13
$\begingroup$

Inspired by this previous question: Findfit doesn't give the good fit; Changing the starting values will not change the results.

Consider the following complex-valued dataset.

f[t_] := b + a/(c + t)
data = Table[f[t] /. {a -> -1 - I, b -> 1 + I, c -> -5 + 2 I}, {t, 1, 10}] 
  + 0.1 RandomComplex[{-1 - I, 1 + I}, 10];
plot = ListPlot[Through@{Re, Im}@data]

enter image description here

Mathematica has no trouble fitting a linear model to it, and successfully finds complex values for the fit parameters.

g[t_] := u + v t;
lfit = FindFit[data, g[t], {u, v}, t]
(* {u -> 1.06445 + 1.59084 I, v -> -0.0604794 - 0.0647658 I} *)
Show[plot, Plot[Evaluate@Through@{Re, Im}@(g[t] /. lfit), {t, 1, 10}]]

enter image description here

It likewise has no trouble fitting the original nonlinear model to it if $c$ is held fixed.

fit = FindFit[data, f[t] /. c -> -5 + 2 I, {a, b}, t]
(* {a -> -1.00813 - 0.888072 I, b -> 0.960261 + 1.01034 I} *)
Show[plot, Plot[Evaluate@Through@{Re, Im}@(f[t] /. c -> -5 + 2 I /. fit), {t, 1, 10}]]

enter image description here

But make $c$ variable and suddenly it can't deal with complex numbers any more.

FindFit[data, f[t], {a, b, c}, t]

FindFit::nrlnum: The function value {0.318749 -1.36562 I,0.294047 -1.31665 I,0.306199 -1.5257 I,0.339789 -1.54803 I,<<3>>,0.59458 -1.00036 I,0.343269 -0.994435 I,0.400584 -0.92625 I} is not a list of real numbers with dimensions {10} at {a,b,c} = {1.,1.,1.}.

What gives?

$\endgroup$
  • 2
    $\begingroup$ Strongly related: "Fitting complex data with NonlinearModelfit." $\endgroup$ – Alexey Popkov Jul 15 '14 at 6:22
  • $\begingroup$ @Alexey: Ah, thanks for the link. I hadn't looked at that question carefully before; it does look like a duplicate. Although none of the answers there have realized why FindFit works in some cases but not in others, as Jens's answer here explains. $\endgroup$ – Rahul Jul 15 '14 at 6:44
13
$\begingroup$

I think what you're seeing is a consequence of the special model that you're using. The parameters a and b appear only linearly, so as long as they are the only fit parameters it is clear that the best approach for FindFit would be to perform a simple LeastSquares calculation. This is a matrix method that works over the complex numbers, and that's why you get complex answers for the fit parameters a and b when you do

fit = FindFit[data, f[t] /. c -> -5 + 2 I, {a, b}, t]

However, when you add c as a parameter, it's no longer possible to go this route. Now, the parameters that are varied in FindFit have to be real. This is because for a nonlinear problem, FindFit uses FindMinimum to minimize a norm function (Norm), and FindMinimum allows only real (or integer) variables.

$\endgroup$
  • $\begingroup$ So this is the reason why explicitly using real-valued parameters and a custom norm-function works. +1 $\endgroup$ – halirutan Jul 15 '14 at 5:39
13
$\begingroup$

For the reason why find fit fails when c is variable, please see the answer of Jens. One way to solve this is to use create the complex target function from real-valued parameters and set the NormFunction explicitely:

f1[t_] := (br + I bi) + (ar + I ai)/(cr + I ci + t)
fit = FindFit[data, f1[t], {ar, ai, br, bi, cr, ci}, t, 
   NormFunction -> (Norm[Re[#*Conjugate[#]]] & )];

Show[plot, Plot[Evaluate@Through@{Re, Im}@(f1[t] /. fit), {t, 1, 10}]]

Mathematica graphics

$\endgroup$
  • $\begingroup$ The strangeness is that FindFit can determine the appropriate norm function in some cases but not in others. $\endgroup$ – Rahul Jul 15 '14 at 5:28
  • $\begingroup$ I know this is beyond the scope of your answer but I was trying to use your method to find the data fit for the original linked question (using his data instead of the generated data in this question), and I got the error of "Failed to converge to the requested accuracy or precision within 100 iterations." screenshot Do you know what I can do to fix this? $\endgroup$ – seismatica Jul 15 '14 at 7:10
  • 3
    $\begingroup$ @seismatica, halirutan: NormFunction -> (Re[#].Re[#] + Im[#].Im[#] &) seems to work better. $\endgroup$ – Rahul Jul 15 '14 at 16:24
  • $\begingroup$ Works like a charm (though I'd love to have someone explain to me why that would work). Thanks @RahulNarain! $\endgroup$ – seismatica Jul 15 '14 at 22:08
  • 1
    $\begingroup$ According to the Documentation, "FindFit by default finds a least-squares fit" and "FindFit effectively uses FindMinimum to minimize a norm of the residual function". But actually they return slightly different answers even if one supplies identical NormFunction and objective function for FindMinimum. But one thing is clear: specifying Method -> "LevenbergMarquardt" for FindFit does not change the output and does not produce an error as it does when one specifies Norm[residual] as objective function for Findminimum. So FindFit internally converts Norm into sum of squares. $\endgroup$ – Alexey Popkov Jul 16 '14 at 7:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.