1 | #!/usr/bin/python -itt
|
---|
2 |
|
---|
3 | import numpy as np
|
---|
4 |
|
---|
5 | from scipy import optimize
|
---|
6 | from numpy import *
|
---|
7 |
|
---|
8 | class Parameter:
|
---|
9 | def __init__(self, value):
|
---|
10 | self.value = value
|
---|
11 |
|
---|
12 | def set(self, value):
|
---|
13 | self.value = value
|
---|
14 |
|
---|
15 | def __call__(self):
|
---|
16 | return self.value
|
---|
17 |
|
---|
18 | def fit(function, parameters, y, x = None):
|
---|
19 | def f(params):
|
---|
20 | i = 0
|
---|
21 | for p in parameters:
|
---|
22 | p.set(params[i])
|
---|
23 | i += 1
|
---|
24 | return y - function(x)
|
---|
25 |
|
---|
26 | if x is None: x = arange(y.shape[0])
|
---|
27 | p = [param() for param in parameters]
|
---|
28 | optimize.leastsq(f, p)
|
---|
29 |
|
---|
30 |
|
---|
31 | class gapdpulse( object ):
|
---|
32 |
|
---|
33 | bsl = -1.0
|
---|
34 | height = 18.0
|
---|
35 | start = 50.
|
---|
36 | rising = 1.2
|
---|
37 | tau1 = 7.
|
---|
38 | tau2 = 25.
|
---|
39 | noise = 0.0001
|
---|
40 | sampling = False
|
---|
41 |
|
---|
42 | def __call__(self, x):
|
---|
43 | if type(x) != type(np.empty(1)):
|
---|
44 | x = np.array(x)
|
---|
45 | val = np.zeros(x.shape)
|
---|
46 | zeros = np.zeros(x.shape)
|
---|
47 |
|
---|
48 | #shortcuts
|
---|
49 | bsl = self.bsl()
|
---|
50 | height = self.height()
|
---|
51 | start = self.start()
|
---|
52 | rising = self.rising()
|
---|
53 | tau1 = self.tau1()
|
---|
54 | tau2 = self.tau2()
|
---|
55 |
|
---|
56 | val += bsl
|
---|
57 |
|
---|
58 |
|
---|
59 |
|
---|
60 | # this is not really the maximum, but about it.... so I call it max
|
---|
61 | max = start + rising * tau1
|
---|
62 |
|
---|
63 | e1 = height * (1 - np.exp(-(x-start)/tau1 ) )
|
---|
64 | e2 = -1 * height * (1 - np.exp(-(x-max)/tau2 ) )
|
---|
65 | val += np.where( x>start , e1, zeros)
|
---|
66 | val += np.where( x>max , e2, zeros)
|
---|
67 |
|
---|
68 | val += np.random.normal(0, self.noise, x.shape)
|
---|
69 |
|
---|
70 | #sampling
|
---|
71 | self.presampling = val.copy()
|
---|
72 | if self.sampling == True:
|
---|
73 | val = np.round(val*2)/2.0
|
---|
74 | self.postsampling = val.copy()
|
---|
75 | return val
|
---|
76 |
|
---|
77 |
|
---|
78 |
|
---|
79 |
|
---|
80 |
|
---|
81 |
|
---|
82 |
|
---|
83 | # Target function, 6 parameters
|
---|
84 | def fitfunc( p, x):
|
---|
85 |
|
---|
86 | # give names to the parameters
|
---|
87 | bsl = p[0]
|
---|
88 | height = p[1]
|
---|
89 | start = p[2]
|
---|
90 | rising = p[3]
|
---|
91 | tau1 = p[4]
|
---|
92 | tau2 = p[5]
|
---|
93 |
|
---|
94 | # these are just helper variables
|
---|
95 | max = start + rising * tau1
|
---|
96 | e1 = height * (1 - np.exp(-(x-start)/tau1 ) ) # the rising edge
|
---|
97 | e2 = -1 * height * (1 - np.exp(-(x-max)/tau2 ) )# the falling edge
|
---|
98 |
|
---|
99 | y = bsl
|
---|
100 | if x > start:
|
---|
101 | y += e1
|
---|
102 | if x > max:
|
---|
103 | y += e2
|
---|
104 | return y
|
---|
105 |
|
---|
106 | def fitfunc2(p, x):
|
---|
107 | # give names to the parameters
|
---|
108 | bsl = p[0] # just the baseline
|
---|
109 | height = p[1] # this is not the pulse height, but the maximum of the discharging edge
|
---|
110 | # it *would* be the pulse height only in case the
|
---|
111 | # recharging process would set in later...
|
---|
112 |
|
---|
113 | start = p[2] # start of avalanche aka start of discharge of diode capacitance
|
---|
114 | stop = p[3] # stop of avalanche, or start of recharging of diode
|
---|
115 | tau1 = p[4] # time constant of discharging process
|
---|
116 | tau2 = p[5] # time constant of recharging process
|
---|
117 |
|
---|
118 | # these are just helper variables
|
---|
119 |
|
---|
120 | e1 = height * (1 - np.exp(-(x-start)/tau1 ) )
|
---|
121 | e2 = -1 * height * (1 - np.exp(-(x-stop)/tau2 ) )
|
---|
122 | zeros = np.zeros(x.shape)
|
---|
123 |
|
---|
124 | y = np.zeros(x.shape)
|
---|
125 | y += bsl
|
---|
126 | y += np.where( x>start , e1, zeros)
|
---|
127 | y += np.where( x>stop , e2, zeros)
|
---|
128 | return y
|
---|
129 |
|
---|
130 |
|
---|
131 |
|
---|
132 | # Distance to the Targetfunction
|
---|
133 | def errfunc( p, x , y):
|
---|
134 | return fitfunc2(p, x) - y
|
---|
135 |
|
---|
136 |
|
---|
137 |
|
---|
138 | if __name__ == '__main__':
|
---|
139 | import matplotlib.pyplot as plt
|
---|
140 | plt.ion()
|
---|
141 | from gen_TH1D import SignalGeneratorCSV
|
---|
142 |
|
---|
143 | g = SignalGeneratorCSV('EdgeOverlayTemplate_AllPixel_1440_0.csv')
|
---|
144 |
|
---|
145 | x = np.linspace(0,300,300,False)
|
---|
146 |
|
---|
147 | fig = plt.figure()
|
---|
148 | plt.grid(True)
|
---|
149 |
|
---|
150 | plt.plot(x,g.csv_maxprob, label='max prob')
|
---|
151 |
|
---|
152 | pnames = ['bsl', 'height', 'start','stop','tau1','tau2']
|
---|
153 |
|
---|
154 | p0 = [-1., 10., 50., 70, 30., 30.] # Initial guess for the parameters
|
---|
155 |
|
---|
156 | # plot function before fitting
|
---|
157 | #plt.plot( x, fitfunc2( p0, x) , '.:')
|
---|
158 |
|
---|
159 | p1, success = optimize.leastsq(errfunc, p0[:], args=(x[0:300], g.csv_maxprob[0:300]))
|
---|
160 |
|
---|
161 | # plot function after fitting
|
---|
162 | plt.plot( x, fitfunc2( p1, x) , '.:')
|
---|
163 | print 'Start values:'
|
---|
164 | for par,name in zip(p0,pnames):
|
---|
165 | print name, ':', par
|
---|
166 | print
|
---|
167 | print
|
---|
168 | print '------------------'
|
---|
169 | print 'Fit parameters'
|
---|
170 | for par,name in zip(p1,pnames):
|
---|
171 | print name, ':', par
|
---|
172 | print '------------------'
|
---|
173 |
|
---|
174 | print 'Fit successfull?:',bool(success)
|
---|
175 |
|
---|
176 | |
---|