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$
4
  • $\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
    Commented Jun 5, 2018 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
    Commented Jun 5, 2018 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
    Commented Jun 5, 2018 at 9:18
  • $\begingroup$ JJH, see ErrorListPlot in the docs and search results on ErrorListPlot on this site $\endgroup$
    – kglr
    Commented Jun 5, 2018 at 9:25

1 Answer 1

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

$\endgroup$
2
  • $\begingroup$ Table might be even more suited for this task Instead of mapping over a range of values $\endgroup$
    – Lukas Lang
    Commented Jun 5, 2018 at 10:19
  • $\begingroup$ Thank you @Mathe172, good point. I added the Table method. $\endgroup$
    – kglr
    Commented Jun 5, 2018 at 10:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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