Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
1  
Strongly related: "Fitting complex data with NonlinearModelfit." –  Alexey Popkov Jul 15 at 6:22
    
@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. –  Rahul Jul 15 at 6:44

2 Answers 2

up vote 10 down vote accepted

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.

share|improve this answer
    
So this is the reason why explicitly using real-valued parameters and a custom norm-function works. +1 –  halirutan Jul 15 at 5:39

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

share|improve this answer
    
The strangeness is that FindFit can determine the appropriate norm function in some cases but not in others. –  Rahul Jul 15 at 5:28
    
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? –  seismatica Jul 15 at 7:10
2  
@seismatica, halirutan: NormFunction -> (Re[#].Re[#] + Im[#].Im[#] &) seems to work better. –  Rahul Jul 15 at 16:24
    
Works like a charm (though I'd love to have someone explain to me why that would work). Thanks @RahulNarain! –  seismatica Jul 15 at 22:08
    
@RahulNarain From researching on NormFunction it seems that you had chosen not do the square root for the typical 2-norm of FindFit--(screenshot). May I know how that managed to overcome the "failed to converge error"? Also this leads me to another fundamental question about curve-fitting that may be obvious for someone stronger in math: why taking the root of the sum of squared differences when fitting curves to data? –  seismatica Jul 15 at 22:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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