1

I have complex data and which I am fitting to a complex formula. In order to use NonlinearModelFit I split the formula and the data into real and imaginary parts.

As usual NonlinearModelFit is sensitive to initial conditions so I have a DynamicModule to help me find these. My problem is that when inside a DynamicModule NonlinearModelFit keeps running and never stops.

I have made a reduced version of the DynamicModule below to show the effect. The local variable numbers never stop increasing.

Why is this? I feel it should just do one operation and stop.

The data is:

data = {{267.761, 0.666697 - 0.117395 I}, {267.794, 0.720659 - 0.140544 I}, 
        {267.827, 0.78293 - 0.165958 I}, {267.861, 0.850505 - 0.19637 I},
        {267.894, 0.933982 - 0.239532 I}, {267.927, 1.04094 - 0.303451 I},
        {267.96, 1.15656 - 0.382384 I}, {267.994, 1.30706 - 0.505816 I}, 
        {268.027, 1.48614 - 0.684103 I}, {268.06, 1.69699 - 0.969217 I}, 
        {268.094, 1.89745 - 1.43193 I}, {268.127,1.9794 - 2.19671 I}, 
        {268.16, 1.49939 - 3.27732 I}, {268.193, 0.0979582 - 4.0018 I}, 
        {268.227, -1.38062 - 3.44199 I}, {268.26, -1.96791 - 2.37086 I}, 
        {268.293, -1.95989 - 1.55105 I}, {268.327, -1.77203 - 1.04211 I},
        {268.36, -1.572 - 0.722879 I}, {268.393, -1.37354 - 0.5245 I}, 
        {268.427, -1.21688 - 0.402393 I}, {268.46, -1.08912 - 0.310994 I},
        {268.493, -0.983056 - 0.249877 I}, {268.526, -0.897219 - 0.205772 I}, 
        {268.56, -0.823682 - 0.173521 I}, {268.593, -0.758923 - 0.150585 I}, 
        {268.626, -0.7049 - 0.127326 I}};

The fitting module is

ClearAll[nlmFit];
nlmFit::usage =  "nlmFit[data,{fnest,\[Zeta]est}] uses nonlinear model fit to get \
                values for constant (h0r,h0i), residue (gr,gi), natural frequency \
                (fn) and damping ratio (\[Zeta]). All data is fitted. Output is the \
                standard NonLinearModelFit";

 nlmFit[data0_, {fnest_, \[Zeta]est_}] := Module[
      {nn, ff, hh, data, model, y, f, hr, hi, rr, ri, fn, \[Zeta]}
  ,
  ff = data0[[All, 1]];
  hh = data0[[All, 2]];
  nn = Length[ff];
  data = Join[
              Transpose[{ff, ConstantArray[0, nn], Re[hh]}],
              Transpose[{ff, ConstantArray[1, nn], Im[hh]}]
             ];

 model = (1 - y) (( f^2 hr + f (rr - 2 fn hr Sqrt[1 - \[Zeta]^2]) + 
   fn (fn hr - ri \[Zeta] - rr Sqrt[1 - \[Zeta]^2]))/( f^2 + fn^2 - 2 f fn Sqrt[1 -
   \[Zeta]^2])) + y ((f^2 hi + f (ri - 2 fn hi Sqrt[1 - \[Zeta]^2]) +  fn (fn hi + 
   rr \[Zeta] - ri Sqrt[1 - \[Zeta]^2]))/(f^2 + fn^2 - 2 f fn Sqrt[1 - \[Zeta]^2]));

 NonlinearModelFit[data, 
                   model, 
                   {{fn, fnest}, {\[Zeta], \[Zeta]est}, rr, ri, hr, hi}, 
                   {f, y}]

 ]

The DynamicModule is

ClearAll[dfit];

dfit[data_, {fn_, \[Zeta]e_}] := DynamicModule[{fitdata},

 Dynamic[fitdata = nlmFit[data, {fn, \[Zeta]e}];

 fitdata["ParameterConfidenceIntervalTable"]]
 ]

To run the DynamicModule

dfit[data, {268, 0.0003}]

...and the output never stops changing. Why is the code running again and again? Thanks

Hugh
  • 16,387
  • 3
  • 31
  • 83
  • 1
    Your example boils down to: DynamicModule[{a}, Dynamic[a = RandomReal[]; a] ]. I'd move assignment outside Dynamic. – Kuba Dec 14 '14 at 12:38
  • @Kuba If I understand the Q, the OP cannot move the assignment outside. Initial conditions are manually set inside Dynamic but that code has been removed. Based on my understanding, what the OP needs is TrackedSymbols (and possibly Refresh). – Michael E2 Dec 14 '14 at 13:31
  • @MichaelE2 I suppose it is the problem with the scheme. If those fn and ZetaE are changed with Slider or something, then there is not need to keep the assignment inside the same Dynamic as the table is. And if it is some kind of automatic loop, Dynamic itself is not really the solution and still I imagine it can be split. However, I do often miss the point of the question ;P – Kuba Dec 14 '14 at 13:36
  • @Kuba Yes, that's possible. The OP says it's a stripped down example, and it's hard to know how faithfully it represents the problem. But the explicit question, which has been answered on the site before, can be answered: An update is triggered every time because fitdata is assigned a new value inside Dynamic and it is a tracked symbol. – Michael E2 Dec 14 '14 at 13:45
  • @MichaelE2 It's more tricky, your description fits: DynamicModule[{a}, Dynamic[a = RandomReal[]] ] but the behaviour is different. Moreover, without DM it is smarter too: Dynamic[a = RandomReal[]; a]. – Kuba Dec 14 '14 at 13:56
  • Dear @Kuba and MichaelE2 thanks for picking this up after so long. Is there anything I can do to help? – Hugh Dec 14 '14 at 14:01
  • @Kuba I believe that is because (1) Random* function "are not ticklish," and (2) a mystery reason. :) My guess about the difference when a is a front-end DynamicModule variable and when a is a kernel variable is complicated, but has to do with which "owns" the variable. – Michael E2 Dec 14 '14 at 14:05
  • @MichaelE2 I must say all I I know about that is what you stated in your comment. But it is not the best answer, isn't it? :) Hugh, can you say how those initial values are provided to Dynamic? – Kuba Dec 14 '14 at 14:15
  • @Kuba By "mystery reason" and "guess" I mean I do not know the best answer. (I assume you mean the answer to why your RandomReal examples behave the way they do). – Michael E2 Dec 14 '14 at 14:18
  • @MichaelE2 The initial values are almost certainly given by sliders. I am trying to dig out the original problem. I have the post but that is in a separate folder from the original problem. – Hugh Dec 14 '14 at 14:21
  • @MichaelE2 Yes, I did and I don't know either :(. – Kuba Dec 14 '14 at 14:24
  • These might be considered duplicates, but this issue can be complicated by the particulars in each situation: 18978, 24212, 33990, 56750. Related: 29678, 49257. – Michael E2 Dec 14 '14 at 14:40
  • 1
    @Hugh You might look at the links in my previous comment just above this one. The solution to your Q is Dynamic[<code>, TrackedSymbols :> {}] or Dynamic[<code>, TrackedSymbols :> {x, y,...}] where x, y,... are your slider variables, but not fitdata. The reason is explained (imo) in some answers to the linked questions. – Michael E2 Dec 14 '14 at 14:45
  • 1
    @Hugh You could (and should) post the solution as an answer. (We actually encourage it.) – Michael E2 Dec 14 '14 at 15:24

1 Answers1

2

I am answering my own question after a suggestion by MichaelE2

Here is a second version of dfit (dfit4) which has Sliders and TrackedSymbols. The sliders are a method of finding appropriate initial conditions. The solution to the problem is to include TrackedSymbols in the Dynamic that calculates the NonLinearModelFit.

 ClearAll[dfit4];
  dfit4[data_] := DynamicModule[{fitdata, fn = 268, \[Zeta]e = 0.0001},
   Column[{
   Row[{"Estimate frequency ", Slider[Dynamic[fn], {0, 400}], 
   Dynamic[fn]}],
   Row[{"Damping ratio ", Slider[Dynamic[\[Zeta]e], {0, 0.001}], 
   Dynamic[\[Zeta]e]}],
    Dynamic[
     fitdata = nlmFit[data, {fn, \[Zeta]e}];
     fitdata["ParameterConfidenceIntervalTable"],
     TrackedSymbols :> {fn, \[Zeta]e}]
   }]
   ]

Thanks to MichaelE2

Hugh
  • 16,387
  • 3
  • 31
  • 83