2
$\begingroup$

I have a code that fits a sine wave to small sections of a large data set and uses this to create an envelope function. I am trying to extract one of the fit parameters for each iteration of the For loop using Reap and Sow. So far I have this code:

Rawdata = Flatten[Import["2018050902.xlsx"]];
l1 = Table[l1, {l1, 0, 538}];
Data1 = MapThread[List, {l1/149.44444444, Rawdata}];
Minifit = Reap[For[(i = 1; j = 11), i < 540 && j < 540, (i += 11; j += 11), 
    nlm = Quiet@ NormalNonlinearModelFit[Part[Rawdata, i + 1 ;; j], (a*(Sin[b t + c]))
    + d, {{a, 1}, {b, 0.3}, {c, 8}, {d, -0.5}}, t]]; 
    Sow[Amp = a /. "BestFitParameters"]]][[2, 1]]
l = Table[l, {l, 5.5, 533.5, 11}];
Bigfit = MapThread[List, {l/149.44444444, Minifit}];
Show[ListLinePlot[Data1, PlotRange -> All, PlotStyle -> {Purple}, Frame -> True, 
FrameLabel -> {"Stage Position (ns)", "Visibility", "55.147mT, No Pulse"}, 
BaseStyle -> {FontFamily -> "Calisto MT", Bold, 20}], 
ListLinePlot[Bigfit, PlotRange -> All, PlotStyle -> {Thick, Black}]]
envfit = Normal[NonlinearModelFit[Bigfit, s Exp[-a t] (Sin[b t + c])^2 + 
f, {{s, 0.5}, {a, 1}, {b, 1.5}, {c, 8}, {f, 0}}, t]]
PeakPos = Part[l/149.44444444, Flatten[Position[Amp, Max[Part[Amp, 8 ;; 49]]]]];
Peak = Max[Amp]; 
Show[ListLinePlot[Bigfit, PlotRange -> All, PlotStyle -> {Thick, Red}], 
ListPlot[{Flatten[{{PeakPos, Peak}}]}, PlotMarkers -> {"x", Large}, PlotStyle -> {Black}]]
Show[Plot[envfit, {t, 0, 3.6}, PlotRange -> All,
PlotStyle -> {Thick, Red, Dashed}, Frame -> True, 
FrameLabel -> {"Stage Position (ns)", "Visibility", "55.147mT, No Pulse"}, 
BaseStyle -> {FontFamily -> "Calisto MT", Bold, 20}, 
PlotLegends -> {Style["20A", GrayLevel[0.35], FontFamily -> "Calisto MT", 20, Bold]}]]

but there seems to be a problem in the Sow command. I want to find the value of the amplitude of the NonlinearModelFit (given by the parameter a) from each iteration of the For Loop but I'm not sure how to get it as a list. The command for finding a is correct as I can move it to outside the For loop and get the final value of a. Should I somehow make the output into a table of values of a or somehow make a into a parameter dependent on t?

I'm also looking into how to get error bars for the fitting model mathematica is using. Is there an obvious way to do this?

$\endgroup$
  • $\begingroup$ does this fix the issue: replace your Minifit = ... with Minifit = Reap[For[(i = 1; j = 11), i < 540 && j < 540, (i += 11; j += 11), nlm = Quiet@ NonlinearModelFit[ Part[Rawdata, i + 1 ;; j], (a*(Sin[b t + c])) + d, {{a, 1}, {b, 0.3}, {c, 8}, {d, -0.5}}, t]; Sow[a /. nlm["BestFitParameters"]]]][[2, 1]]? $\endgroup$ – kglr Jun 5 '18 at 8:51
  • $\begingroup$ an alternative way to get Minifit without a For loop and Reap/Sow is Minifit2 = a /. Quiet@ NonlinearModelFit[ Part[Rawdata, # ;; # + 9], (a*(Sin[b t + c])) + d, {{a, 1}, {b, 0.3}, {c, 8}, {d, -0.5}}, t][ "BestFitParameters"] & /@ Range[2, 539, 11] $\endgroup$ – kglr Jun 5 '18 at 9:12
  • $\begingroup$ That does work thanks, although I might need to look for a more accurate fit as using the amplitude does not always give an accurate envelope function. Do you know how I could fit the error bars? $\endgroup$ – JJH Jun 5 '18 at 9:18
  • $\begingroup$ JJH, see ErrorListPlot in the docs and search results on ErrorListPlot on this site $\endgroup$ – kglr Jun 5 '18 at 9:25
2
$\begingroup$

Fixing the errors in the relevant part of the code:

Rawdata =(*Flatten[Import["2018050902.xlsx"]];*)RandomReal[100, 539];
Minifit = Reap[For[(i = 1; j = 11), i < 540 && j < 540, (i += 11; j += 11), 
  nlm = Quiet@ NonlinearModelFit[Part[Rawdata, i + 1 ;; j], (a*(Sin[b t + c])) + d, 
  {{a, 1}, {b, 0.3}, {c, 8}, {d, -0.5}}, t]; Sow[a /. nlm["BestFitParameters"]]]][[2, 1]]

{14.1488, 18.37, 29.298, -23.3025, 40.3351, -27.7655, -31.2595, -35.5589, 42612.5, -26.9031, 18.2177, -24.6053, -13.7048, -22346.2, 18.816, -12.9398, -19533.9, 20.0164, -15.1908, 28.9609, -12.5952, -4532.96, -29.2517, 29.7385, -30.7523, -3519.99, -31.2898, -16.6772, 28.8027, -22.4752, 14.7128, -28.9536, -30.075, 27.8148, -17.35, 29.5031, -21369.8, 48.5057, 3849.14, 26.5289, 17.5288, -13.1019, -27.8391, 14.5342, 28658.8, -1394.54, -22.5329, 29.4901, -1477.05}

Alternative ways without a For loop and Reap/Sow:

Minifit2 = a /. Quiet @ NonlinearModelFit[Part[Rawdata, # ;; # + 9],
 (a*(Sin[b t + c])) + d, {{a, 1}, {b, 0.3}, {c, 8}, {d, -0.5}}, t]["BestFitParameters"]&/@
   Range[2, 539, 11];
Minifit3 = Table[a /. Quiet@NonlinearModelFit[Part[Rawdata, i ;; i + 9], 
  (a*(Sin[b t + c])) + d, {{a, 1}, {b, 0.3}, {c, 8}, {d, -0.5}}, t][ "BestFitParameters"],
   {i, Range[2, 539, 11]}];
Minifit == Minifit2 == Minifit3

True

| improve this answer | |
$\endgroup$
  • $\begingroup$ Table might be even more suited for this task Instead of mapping over a range of values $\endgroup$ – Lukas Lang Jun 5 '18 at 10:19
  • $\begingroup$ Thank you @Mathe172, good point. I added the Table method. $\endgroup$ – kglr Jun 5 '18 at 10: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.