#!/usr/bin/env python # ----------------------------------------------------------------------------------- # # # ROOT macro for reading text (ASCII) files and fitting data written. # # This exercise is about more advanced fitting of data. The outset is the simplest # possible function that even remotely does the job, which is then expanded to # accommodate all the features present in the data fitted. # The data is from a damped harmonic oscillator, in this case a spring hanging with # a weight but possibly also a round piece of cardboard, which increases the drag. # # The formula for the position (d) as a function of time (t) of a simple underdamped # harmonic oscillator can be found here: d(t) = A * sin(w*t+phase) * exp(-gamma*t) # # Author: Troels C. Petersen (NBI) # Email: petersen@nbi.dk # Date: 6th of January 2016 # # ----------------------------------------------------------------------------------- # from ROOT import * from array import array # Setting what to be shown in statistics box: gStyle.SetOptStat("emr") gStyle.SetOptFit(1111) SavePlots = True verbose = True Nverbose = 10 # ----------------------------------------------------------------------------------- # # 1st data set: # ----------------------------------------------------------------------------------- # # Define files, lists, counters and read data: file = "data_HarmOsc1.txt" time0 = 0.0 # For ensuring that time starts at 0.0s! time = [] dist = [] Nread = 0 # Loop over files and open them with open( file, 'r' ) as f : # Loop over lines and extract variables of interest for line in f: line = line.strip() columns = line.split() if (len(columns) == 2) : # Put the values read into lists: if (Nread == 0) : time0 = float(columns[0]) time.append(float(columns[0]) - time0) dist.append(float(columns[1])) if (verbose and Nread < Nverbose) : print " Time = %6.3f Dist = %6.3f "%(time[-1], dist[-1]) Nread += 1 else : print " Error: Strange values/lines read from data file!" f.close() print " Number of entries read: %d Time of last read: %6.3f"%(Nread, time[Nread-1]) # Plot the data: # -------------------------------------- # tmax = 38.0 # Maximum of time range fitted t = array( 'f', [0.0]*Nread ) et = array( 'f', [0.0]*Nread ) d = array( 'f', [0.0]*Nread ) ed = array( 'f', [0.0]*Nread ) # Fill the arrays from the lists and also assign uncertainties: # ------------------------------------------------------------- for i in range( Nread ) : t[i] = time[i] et[i] = 0.0 d[i] = dist[i] ed[i] = 0.0035 if not ((-0.001 < time[i] < 100.0) and (-5.0 < dist[i] < 5.0)) : print "Warning: Strange value for time and/or dist!", i, time[i], dist[i] # Make a graph of the data: graph_osc = TGraphErrors(Nread, t, d, et, ed) # Fit this graph with a simple and an advanced harmonic oscillator: fit1 = TF1("fit1", "[0] + [1] * exp(-[2]*x) * cos([3]*x + [4])", 0.0, tmax) fit1.SetParameters(-0.1, 0.6, 0.007, 9.6, 2.8) fit1.SetLineColor(kRed) fit1.SetLineWidth(2) fit1.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! graph_osc.Fit("fit1", "R") fit2 = TF1("fit2", "[0] + [1] * exp(-[2]*x) * cos([3]*x+[4] + [5]*x*x) * (1.0 + [6]*cos([7]*x+[8]))", 0.0, tmax) fit2.SetParameters(-0.1, 0.6, 0.007, 9.6, 2.8, 0.0, 0.002, 2.6, -0.42); fit2.SetLineColor(kBlue) fit2.SetLineWidth(2) fit2.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! graph_osc.Fit("fit2", "R+") # Calculate residuals and put into histograms: dd1 = array( 'f', [0.0]*Nread ) dd2 = array( 'f', [0.0]*Nread ) hist_dd1 = TH1F("hist_dd1", "Residuals of fit1", 120, -0.03, 0.03) hist_dd2 = TH1F("hist_dd2", "Residuals of fit2", 120, -0.03, 0.03) for i in range( Nread ) : dd1[i] = d[i] - fit1.Eval(t[i]) dd2[i] = d[i] - fit2.Eval(t[i]) hist_dd1.Fill(dd1[i]) hist_dd2.Fill(dd2[i]) if (abs(dd1[i]) > 0.020) : print " Large residual: t = %6.3f d = %6.3f dd1 = %6.3f"%(t[i], d[i], dd1[i]) if (abs(dd2[i]) > 0.012) : print " Large residual: t = %6.3f d = %6.3f dd2 = %6.3f"%(t[i], d[i], dd2[i]) graph_res1 = TGraphErrors(Nread, t, dd1, et, ed) graph_res2 = TGraphErrors(Nread, t, dd2, et, ed) # Make a white canvas and draw the data in: # ----------------------------------------- c0 = TCanvas("c0","", 20, 20, 1400, 700) # Plot the oscillation: padOsc = TPad("padOsc", "", 0.0, 0.35, 1.0, 1.0) padOsc.SetLeftMargin(1.1) padOsc.SetBottomMargin(0.0) padOsc.Draw() padOsc.cd() graph_osc.SetTitle("") graph_osc.GetXaxis().SetTitle("Time elapsed [s]") graph_osc.GetYaxis().SetTitle("Position") graph_osc.GetXaxis().SetRangeUser(0.0, time[Nread-1]+0.25) # Set the plotting range! graph_osc.GetYaxis().SetRangeUser(-0.75, 0.8) # Set the plotting range! graph_osc.SetLineColor(kBlack) graph_osc.SetLineWidth(2) graph_osc.SetMarkerStyle(20) graph_osc.SetMarkerColor(kBlack) graph_osc.SetMarkerSize(0.5) graph_osc.Draw("AP") # Plot the residuals of the two fits: c0.cd() padRes = TPad("padRes", "", 0.0, 0.0, 1.0, 0.35) padRes.SetLeftMargin(1.1) padRes.SetTopMargin(0.00) padRes.SetBottomMargin(0.27) padRes.Draw() padRes.cd() graph_res1.SetTitle("") graph_res1.GetXaxis().SetTitle("Time elapsed [s]") graph_res1.GetYaxis().SetTitle("Position residual") graph_res1.GetXaxis().SetRangeUser(0.0, time[Nread-1]+0.25) # Set the plotting range! graph_res1.SetLineColor(kRed) graph_res1.SetLineWidth(2) graph_res1.SetMarkerStyle(20) graph_res1.SetMarkerColor(kRed) graph_res1.SetMarkerSize(0.5) graph_res1.Draw("AP") graph_res2.SetTitle("") graph_res2.GetXaxis().SetRangeUser(0.0, time[Nread-1]+0.25) # Set the plotting range! graph_res2.SetLineColor(kBlue) graph_res2.SetLineWidth(2) graph_res2.SetMarkerStyle(20) graph_res2.SetMarkerColor(kBlue) graph_res2.SetMarkerSize(0.5) graph_res2.Draw("P same") line_zero = TLine(0.0, 0.0, tmax, 0.0) line_zero.SetLineColor(kWhite) line_zero.SetLineWidth(2) line_zero.SetLineStyle(3) line_zero.Draw() # Plot histograms of the residuals of the two fits: c0.cd() padHist = TPad("padHist", "", 0.78, 0.38, 0.98, 0.73) padHist.SetLeftMargin(0.0) padHist.SetRightMargin(0.0) padHist.SetTopMargin(0.0) padHist.SetBottomMargin(0.0) padHist.Draw() padHist.cd() hist_dd2.SetLineColor(kBlue) hist_dd2.SetLineWidth(2) hist_dd2.Draw() hist_dd1.SetLineColor(kRed) hist_dd1.SetLineWidth(2) hist_dd1.Draw("same") c0.Update() if (SavePlots) : c0.SaveAs("Fit_HarmOsc1.pdf") # ----------------------------------------------------------------------------------- # # 2nd data set - Overdamped harmonic oscillator: # ----------------------------------------------------------------------------------- # # Define files, lists, counters and read data: file = "data_HarmOsc2.txt" time0 = 0.0 # For ensuring that time starts at 0.0s! time = [] dist = [] Nread = 0 # Loop over files and open them with open( file, 'r' ) as f : # Loop over lines and extract variables of interest for line in f: line = line.strip() columns = line.split() if (len(columns) == 2) : # Put the values read into lists: if (Nread == 0) : time0 = float(columns[0]) time.append(float(columns[0]) - time0) dist.append(float(columns[1])) if (verbose and Nread < Nverbose) : print " Time = %6.3f Dist = %6.3f "%(time[-1], dist[-1]) Nread += 1 else : print " Error: Strange values/lines read from data file!" f.close() print " Number of entries read: %d Time of last read: %6.3f"%(Nread, time[Nread-1]) # Plot the data: # -------------------------------------- # tmax = 36.0 # Maximum of time range fitted t = array( 'f', [0.0]*Nread ) et = array( 'f', [0.0]*Nread ) d = array( 'f', [0.0]*Nread ) ed = array( 'f', [0.0]*Nread ) # Fill the arrays from the lists and also assign uncertainties: # ------------------------------------------------------------- for i in range( Nread ) : t[i] = time[i] et[i] = 0.0 d[i] = dist[i] ed[i] = 0.0025 if not ((-0.001 < time[i] < 100.0) and (-5.0 < dist[i] < 5.0)) : print "Warning: Strange value for time and/or dist!", i, time[i], dist[i] # Make a graph of the data: graph_osc = TGraphErrors(Nread, t, d, et, ed) # Fit this graph with a simple and an advanced harmonic oscillator: fit1 = TF1("fit1", "[0] + [1] * exp(-[2]*x) * cos([3] + [4]*x)", 0.0, tmax) fit1.SetParameters(0.038, 0.19, 0.104, -1.0, 8.97) fit1.SetLineColor(kRed) fit1.SetLineWidth(2) fit1.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! graph_osc.Fit("fit1", "R") fit2 = TF1("fit2", "[0] + ([1]*exp(-[2]*x) + [9]*exp(-[10]*x)) * cos([3]+[4]*x+[5]*x*x) * (1.0 + [6]*cos([7]*x+[8]))", 0.0, tmax) fit2.SetParameters(0.038, 0.19, 0.104, -1.0, 8.97, 0.0007, 0.06, 0.4, 1.0, 0.02, 0.01) fit2.SetLineColor(kBlue) fit2.SetLineWidth(2) fit2.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! graph_osc.Fit("fit2", "R+") # Calculate residuals and put into histograms: dd1 = array( 'f', [0.0]*Nread ) dd2 = array( 'f', [0.0]*Nread ) hist_dd1 = TH1F("hist_dd1", "Residuals of fit1", 120, -0.03, 0.03) hist_dd2 = TH1F("hist_dd2", "Residuals of fit2", 120, -0.03, 0.03) for i in range( Nread ) : dd1[i] = d[i] - fit1.Eval(t[i]) dd2[i] = d[i] - fit2.Eval(t[i]) hist_dd1.Fill(dd1[i]) hist_dd2.Fill(dd2[i]) if (abs(dd1[i]) > 0.020) : print " Large residual: t = %6.3f d = %6.3f dd1 = %6.3f"%(t[i], d[i], dd1[i]) if (abs(dd2[i]) > 0.012) : print " Large residual: t = %6.3f d = %6.3f dd2 = %6.3f"%(t[i], d[i], dd2[i]) graph_res1 = TGraphErrors(Nread, t, dd1, et, ed) graph_res2 = TGraphErrors(Nread, t, dd2, et, ed) # Make a white canvas and draw the data in: # ----------------------------------------- c1 = TCanvas("c1","", 20, 50, 1400, 700) # Plot the oscillation: padOsc = TPad("padOsc", "", 0.0, 0.35, 1.0, 1.0) padOsc.SetLeftMargin(1.1) padOsc.SetBottomMargin(0.0) padOsc.Draw() padOsc.cd() graph_osc.SetTitle("") graph_osc.GetXaxis().SetTitle("Time elapsed [s]") graph_osc.GetYaxis().SetTitle("Position") graph_osc.GetXaxis().SetRangeUser(0.0, time[Nread-1]+0.25) # Set the plotting range! graph_osc.GetYaxis().SetRangeUser(-0.20, 0.25) # Set the plotting range! graph_osc.SetLineColor(kBlack) graph_osc.SetLineWidth(2) graph_osc.SetMarkerStyle(20) graph_osc.SetMarkerColor(kBlack) graph_osc.SetMarkerSize(0.5) graph_osc.Draw("AP") # Plot the residuals of the two fits: c1.cd() padRes = TPad("padRes", "", 0.0, 0.0, 1.0, 0.35) padRes.SetLeftMargin(1.1) padRes.SetTopMargin(0.00) padRes.SetBottomMargin(0.27) padRes.Draw() padRes.cd() graph_res1.SetTitle("") graph_res1.GetXaxis().SetTitle("Time elapsed [s]") graph_res1.GetYaxis().SetTitle("Position residual") graph_res1.GetXaxis().SetRangeUser(0.0, time[Nread-1]+0.25) # Set the plotting range! graph_res1.SetLineColor(kRed) graph_res1.SetLineWidth(2) graph_res1.SetMarkerStyle(20) graph_res1.SetMarkerColor(kRed) graph_res1.SetMarkerSize(0.5) graph_res1.Draw("AP") graph_res2.SetTitle("") graph_res2.GetXaxis().SetRangeUser(0.0, time[Nread-1]+0.25) # Set the plotting range! graph_res2.SetLineColor(kBlue) graph_res2.SetLineWidth(2) graph_res2.SetMarkerStyle(20) graph_res2.SetMarkerColor(kBlue) graph_res2.SetMarkerSize(0.5) graph_res2.Draw("P same") line_zero = TLine(0.0, 0.0, tmax, 0.0) line_zero.SetLineColor(kWhite) line_zero.SetLineWidth(2) line_zero.SetLineStyle(3) line_zero.Draw() # Plot histograms of the residuals of the two fits: c1.cd() padHist = TPad("padHist", "", 0.78, 0.38, 0.98, 0.73) padHist.SetLeftMargin(0.0) padHist.SetRightMargin(0.0) padHist.SetTopMargin(0.0) padHist.SetBottomMargin(0.0) padHist.Draw() padHist.cd() hist_dd2.SetLineColor(kBlue) hist_dd2.SetLineWidth(2) hist_dd2.Draw() hist_dd1.SetLineColor(kRed) hist_dd1.SetLineWidth(2) hist_dd1.Draw("same") c1.Update() if (SavePlots) : c1.SaveAs("Fit_HarmOsc2.pdf") # ----------------------------------------------------------------------------------- # # 3rd data set - Slowed harmonic oscillator (sliding against steel): # ----------------------------------------------------------------------------------- # # Define files, lists, counters and read data: file = "data_HarmOsc3.txt" time0 = 0.0 # For ensuring that time starts at 0.0s! time = [] dist = [] Nread = 0 # Loop over files and open them with open( file, 'r' ) as f : # Loop over lines and extract variables of interest for line in f: line = line.strip() columns = line.split() if (len(columns) == 2) : # Put the values read into lists: if (Nread == 0) : time0 = float(columns[0]) time.append(float(columns[0]) - time0) dist.append(float(columns[1])) if (verbose and Nread < Nverbose) : print " Time = %6.3f Dist = %6.3f "%(time[-1], dist[-1]) Nread += 1 else : print " Error: Strange values/lines read from data file!" f.close() print " Number of entries read: %d Time of last read: %6.3f"%(Nread, time[Nread-1]) # Plot the data: # -------------------------------------- # tmax = 14.0 # Maximum of time range fitted t = array( 'f', [0.0]*Nread ) et = array( 'f', [0.0]*Nread ) d = array( 'f', [0.0]*Nread ) ed = array( 'f', [0.0]*Nread ) # Fill the arrays from the lists and also assign uncertainties: # ------------------------------------------------------------- for i in range( Nread ) : t[i] = time[i] et[i] = 0.0 d[i] = dist[i] ed[i] = 0.0025 if not ((-0.001 < time[i] < 100.0) and (-5.0 < dist[i] < 5.0)) : print "Warning: Strange value for time and/or dist!", i, time[i], dist[i] # Make a graph of the data: graph_osc = TGraphErrors(Nread, t, d, et, ed) # Fit this graph with a simple and an advanced harmonic oscillator: fit1 = TF1("fit1", "[0] + ([1] + [2]*x) * cos([3] + [4]*x)", 0.0, tmax) fit1.SetParameters(0.038, 0.19, 0.104, -1.0, 8.97) fit1.SetLineColor(kRed) fit1.SetLineWidth(2) fit1.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! graph_osc.Fit("fit1", "R") def fit_func2(x,p) : if (x[0] < p[5]) : return p[0] + (p[1] + p[2]*x[0]) * cos(p[3] + p[4]*x[0]) else : return p[0] + (p[1] + p[2]*p[5]) * exp(p[2]*x[0]) * cos(p[3] + p[4]*x[0]) fit2 = TF1("fit2", fit_func2, 0.0, tmax, 6) fit2.SetParameters(0.038, 0.19, 0.104, -1.0, 8.97, 11.5) fit2.SetLineColor(kBlue) fit2.SetLineWidth(2) fit2.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! # graph_osc.Fit("fit2", "R+") # Calculate residuals and put into histograms: dd1 = array( 'f', [0.0]*Nread ) #dd2 = array( 'f', [0.0]*Nread ) hist_dd1 = TH1F("hist_dd1", "Residuals of fit1", 100, -0.10, 0.10) #hist_dd2 = TH1F("hist_dd2", "Residuals of fit2", 100, -0.10, 0.10) for i in range( Nread ) : dd1[i] = d[i] - fit1.Eval(t[i]) #dd2[i] = d[i] - fit2.Eval(t[i]) hist_dd1.Fill(dd1[i]) #hist_dd2.Fill(dd2[i]) if (abs(dd1[i]) > 0.20) : print " Large residual: t = %6.3f d = %6.3f dd1 = %6.3f"%(t[i], d[i], dd1[i]) #if (abs(dd2[i]) > 0.12) : # print " Large residual: t = %6.3f d = %6.3f dd2 = %6.3f"%(t[i], d[i], dd2[i]) graph_res1 = TGraphErrors(Nread, t, dd1, et, ed) #graph_res2 = TGraphErrors(Nread, t, dd2, et, ed) # Make a white canvas and draw the data in: # ----------------------------------------- c2 = TCanvas("c2","", 20, 80, 1400, 700) # Plot the oscillation: padOsc = TPad("padOsc", "", 0.0, 0.35, 1.0, 1.0) padOsc.SetLeftMargin(1.1) padOsc.SetBottomMargin(0.0) padOsc.Draw() padOsc.cd() graph_osc.SetTitle("") graph_osc.GetXaxis().SetTitle("Time elapsed [s]") graph_osc.GetYaxis().SetTitle("Position") graph_osc.GetXaxis().SetRangeUser(0.0, time[Nread-1]+1.0) # Set the plotting range! graph_osc.GetYaxis().SetRangeUser(-2.00, 1.00) # Set the plotting range! graph_osc.SetLineColor(kBlack) graph_osc.SetLineWidth(2) graph_osc.SetMarkerStyle(20) graph_osc.SetMarkerColor(kBlack) graph_osc.SetMarkerSize(0.5) graph_osc.Draw("AP") # Plot the residuals of the two fits: c2.cd() padRes = TPad("padRes", "", 0.0, 0.0, 1.0, 0.35) padRes.SetLeftMargin(1.1) padRes.SetTopMargin(0.00) padRes.SetBottomMargin(0.27) padRes.Draw() padRes.cd() graph_res1.SetTitle("") graph_res1.GetXaxis().SetTitle("Time elapsed [s]") graph_res1.GetYaxis().SetTitle("Position residual") graph_res1.GetXaxis().SetRangeUser(0.0, time[Nread-1]+1.0) # Set the plotting range! graph_res1.SetLineColor(kRed) graph_res1.SetLineWidth(2) graph_res1.SetMarkerStyle(20) graph_res1.SetMarkerColor(kRed) graph_res1.SetMarkerSize(0.5) graph_res1.Draw("AP") """ graph_res2.SetTitle("") graph_res2.GetXaxis().SetRangeUser(0.0, time[Nread-1]+1.0) # Set the plotting range! graph_res2.SetLineColor(kBlue) graph_res2.SetLineWidth(2) graph_res2.SetMarkerStyle(20) graph_res2.SetMarkerColor(kBlue) graph_res2.SetMarkerSize(0.5) graph_res2.Draw("P same") """ line_zero = TLine(0.0, 0.0, tmax, 0.0) line_zero.SetLineColor(kWhite) line_zero.SetLineWidth(2) line_zero.SetLineStyle(3) line_zero.Draw() # Plot histograms of the residuals of the two fits: c2.cd() padHist = TPad("padHist", "", 0.78, 0.28, 0.98, 0.58) padHist.SetLeftMargin(0.0) padHist.SetRightMargin(0.0) padHist.SetTopMargin(0.0) padHist.SetBottomMargin(0.0) padHist.Draw() padHist.cd() #hist_dd2.SetLineColor(kBlue) #hist_dd2.SetLineWidth(2) #hist_dd2.Draw() hist_dd1.SetLineColor(kRed) hist_dd1.SetLineWidth(2) hist_dd1.Draw("same") c2.Update() if (SavePlots) : c2.SaveAs("Fit_HarmOsc3.pdf") raw_input( ' ... Press enter to exit ... ' ) # ----------------------------------------------------------------------------------- # # # Looking at the plot of data from the file "data_HarmOsc1.txt", there is little doubt # that it is oscillating, and looking closer you will also see the slight damping. # # Questions: # ---------- # 1) Look at the data file and plot and see if you can by eye (or simple fits) estimate # the size of the uncertainty of the points. It is not easy, but you should be able # to get it to within a factor of 2-3. Try for 5-10 minutes and discuss it with your # neighbor before reading on! # # - - - - - - 5-10 minutes (success or failure) later - - - - - - # # If you didn't know how to estimate this uncertainty, then try to zoom in on a very # small part of the curve, where it should be possible to fit it with a line, or # possibly a 2nd or 3rd degree polynomial. Do so, and since you know that for a small # enough range of the data, this will be a reasonable PDF to use, extract the error # from the RMS of the residuals, which is roughly equivalent to choosing the errors, # that gives you a reasonable Chi2. If you want to check this, then using this error # for all points, see if it still fits well in some other range. # # 2) Once you have tried, set the error to 0.005, and try to fit a damped harmonic # oscillator. You will have to write the function yourself. Do so and run the fit # before reading on. # # - - - - - - 5-10 minutes (success or failure) later - - - - - - # # Did you manage to write the fitting function? Also, did you remember to put in a # parameter taking care of the offset from zero? If not, then look at the bottom of # this page, and "borrow" the parts that you need. Now run this fit, and see what # happens. # # - - - - - - 5-10 minutes (success or failure) later - - - - - - # # 3) Did the fit converge? I imagine that it didn't (thought it might have), and my first # guess on why (apart from copying the below wrongly) would be initial parameters. You # need to set the initial parameters quite accurately, for the fit to work. Think about # this, i.e. in a 5D parameter space, how hard it is to find just the correct frequency # when all you got is a Chi2 value, and being just 5% wrong or so will give you nothing # of value? # So now try to evaluate what some good initial values for the fit would be. You can # start by simply making educated guesses, but if that fails, you can instead draw the # function choosing some parameters, until it starts looking like the data you have. # # 4) Try to fit only the range 20s-22s, and see how significant the damping is. Would # you from only two seconds data be able to tell, that there is a damping, and if # so, by how many sigma? # # # # ---------------- Now consider the data file "data_HarmOsc2.txt" --------------- # # 5) Now consider the data file "data_HarmOsc2.txt", and set the uncertainty on the # distance to be 0.0025. Again, make a simple harmonic oscillator fit run. # Now your job is to expand on the fitting function and introduce terms to include # various effects and thus reduce the Chi2. # Set your fit to the range [0.005,36.005], and see how low a Chi2 you can get. # # 6) Can you detect a change in the distance uncertainty as a function of time? # I.e. does the errors needed to get a reasonable/constant Chi2 get better or worse # if you fit small ranges of time early and late in the experiment. # # # # ---------------- Now consider the data file "data_HarmOsc3.txt" --------------- # # 7) The data file "data_HarmOsc3.txt" contains a different type of damping in the # oscillation. Fit this, and determine at which point the oscillation stops. # # # ----------------------------------------------------------------------------------- # # # You need to write this functional form of a damped harmonic oscillator: # def func_osc(x, par) : # return par[0] + par[1]*sin(par[2]*x[0]+par[3])*exp(-par[4]*x[0]) # # fit = TF1("fit", func_osc, 0.0, time[Nread-1], 5) # fit.SetLineColor(kRed) # fit.SetLineWidth(2) # fit.SetNpx(2000) # This is just to make sure that the function is drawn smoothly enough! # graph.Fit("fit", "R")