Diana Software
QBiComponentOptimumFilter.cc
Go to the documentation of this file.
2 #include "QError.hh"
3 #include "QMatrix.hh"
4 #include "QRealComplexFFT.hh"
5 #define EXTRA_JITTER 1
6 
7 // EXTRA_JITTERS:
8 // 1: minimum number needed for interpolation
9 // 2: more point to see if we have a minimum at the boundary (enable nice parabola)
10 
11 using std::vector;
12 using namespace Diana;
13 
14 QBiComponentOptimumFilter::QBiComponentOptimumFilter(const QVector& ap1, const QVector& ap2, const QVector& an, size_t maxJitter, bool diff) :
15 fIsDiff(diff),
16 fMaxJitter(maxJitter),
17 fTransformer(0)
18 {
20  fSize = ap1.Size();
21  if(ap2.Size() != fSize || an.Size() != fSize) {
22  QError err(QERR_SIZE_NOT_MATCH,__FILE__,__LINE__,"Size of input QVectors mismatches");
23  DianaThrow(err);
24  }
26 
27  QVector ap1n = NormalizeVector(ap1);
28  QVector ap2n = NormalizeVector(ap2);
29  fAveragePulse1 = ap1n;
30  fAveragePulse2 = ap2n;
31 
32  fAvgPulseIntegral1= ap1n.Sum(ap1n.Size(),0);
33  fAvgPulseIntegral2= ap2n.Sum(ap2n.Size(),0);
34 
35  if(fIsDiff) {
36  ap1n.Differentiate();
37  ap2n.Differentiate();
38 
39  QVector andi = an;
40  for(size_t i = 1 ; i < fSize;i++) {
41  if(i<=fSize/2) andi[i]*=2.*(1.-cos(2.*M_PI/(fSize)*i));
42  else andi[i]*=2.*(1.-cos(2.*M_PI/(fSize)*(fSize-i)));
43  }
44  fAverageNoise = andi;
45  } else {
46  fAverageNoise = an;
47  }
48  fAverageNoise[0] = 0;
49  BuildFilter(ap1n,ap2n);
50 }
51 
53 {
54  if(fTransformer) {
55  delete fTransformer;
56  fTransformer = 0;
57  }
58 }
59 
60 QError QBiComponentOptimumFilter::Filter(const Diana::QVector& p)
61 {
63  if(p.Size() != fSize) {
64  QError err(QERR_SIZE_NOT_MATCH,__FILE__,__LINE__,"Size of filtered QVector is not correct");
65  fCheck = err;
66  return err;
67  }
68  fFiltered1.Clear();
69  fFiltered2.Clear();
70  QVectorC pf,pf1,pf2;
71  if(fIsDiff) {
72  QVector pd = p;
73  pd.Differentiate();
74  fTransformer->TransformToFreq(pd,pf);
75  } else {
76  fTransformer->TransformToFreq(p,pf);
77  }
78  pf1 = fFilter1.Mult(pf);
79  pf2 = fFilter2.Mult(pf);
80  fTransformer->TransformFromFreq(pf1,fFiltered1);
81  fTransformer->TransformFromFreq(pf2,fFiltered2);
82 
84 
85  return fCheck;
86 }
87 void QBiComponentOptimumFilter::GetFiltered(Diana::QVector& f1, Diana::QVector& f2) const
88 {
90  f1 = fFiltered1;
91  f2 = fFiltered2;
92 }
93 const std::vector<double>& QBiComponentOptimumFilter::GetChiSquareWithJitter() const
94 {
96  return fChiSquareWithJitter;
97 }
98 
100 {
102  return fJitters[fOptimumJitter] ;
103 }
104 
106 {
109 }
110 
111 void QBiComponentOptimumFilter::GetAmplitude(double& a1, double& a2, double& integral) const
112 {
114  a1 = fAmplitude1;
115  a2 = fAmplitude2;
117 }
118 
119 QError QBiComponentOptimumFilter::GetInterpolated(double& intJitter, double& inta1, double& inta2,double& integral) const
120 {
122  double xa = fJitters[fOptimumJitter-1];
123  double xb = fJitters[fOptimumJitter];
124  double xc = fJitters[fOptimumJitter+1];
125  double ya = fChiSquareWithJitter[fOptimumJitter-1];
127  double yc = fChiSquareWithJitter[fOptimumJitter+1];
128  if(yb>ya || yb>yc) {
130  err.SetDescription("Chisquare not at minimum, interpolation not possible");
131  return err;
132  }
133 
134 
135 
136  double detA = xa*xa*(xb-xc)-xb*xb*(xa-xc)+xc*xc*(xa-xb);
137  double detA1 = ya*(xb-xc)-yb*(xa-xc)+yc*(xa-xb);
138  double detA2 = xa*xa*(yb-yc)-xb*xb*(ya-yc)+xc*xc*(ya-yb);
139  //double detA3 = xa*xa*(xb*yc-yb*xc)-xb*xb*(xa*yc-ya*xc)+xc*xc*(xa*yb-ya*xb);
140 
141  double p0 = detA1/detA;
142  double p1 = detA2/detA;
143 // double p2 = detA3/detA;
144 
145  intJitter = -p1/2./p0;
146  int low = floor(intJitter);
147  int high = ceil (intJitter);
148  double x = intJitter-low;
149  if(low < 0) low += fSize;
150  if(high < 0) high += fSize;
151  double a1Low = fFiltered1[low];
152  double a1High = fFiltered1[high];
153  double a2Low = fFiltered2[low];
154  double a2High = fFiltered2[high];
155  inta1 = (a1High-a1Low)*x+a1Low;
156  inta2 = (a2High-a2Low)*x+a2Low;
157  integral = fAvgPulseIntegral1*inta1+fAvgPulseIntegral2*inta2;
158  return QERR_SUCCESS;
159 }
160 
161 QVector QBiComponentOptimumFilter::NormalizeVector(const QVector& vec) const
162 {
163  QVector ret = vec;
164  QVector baseline(ret.Size());
165  baseline.Initialize(ret[0]);
166  ret -= baseline;
167  ret /= ret.GetMax();
168  return ret;
169 }
170 
171 void QBiComponentOptimumFilter::BuildFilter(const QVector& ap1, const QVector& ap2)
172 {
173  const size_t size = ap1.Size();
174 
175  QVectorC ap1f,ap2f;
176  fTransformer->TransformToFreq(ap1,ap1f);
177  fTransformer->TransformToFreq(ap2,ap2f);
178 
179 
180  Diana::QMatrix M(2,2);
181  M(0,0) = (ap1f.GetModulusSquare().Div(fAverageNoise)).Sum(size-1,1);
182  M(0,1) = ((ap1f.Conj().Mult(ap2f)).Re().Div(fAverageNoise)).Sum(size-1,1);
183  M(1,0) = M(0,1);
184  M(1,1) = (ap2f.GetModulusSquare().Div(fAverageNoise)).Sum(size-1,1);
185  M.Invert();
186 
187  QVectorC anc(size);
188  anc.Initialize(0,0);
189  anc.SetRe(fAverageNoise);
190 
191  fFilter1 = (M(0,0)*ap1f.Conj()+M(0,1)*ap2f.Conj()).Div(anc);
192  fFilter2 = (M(1,0)*ap1f.Conj()+M(1,1)*ap2f.Conj()).Div(anc);
193 
194  fFilteredRMS1 = ((fFilter1.Mult(anc)).GetModulusSquare().Div(fAverageNoise)).Sum(size-1,1);
196  fFilteredRMS2 = ((fFilter2.Mult(anc)).GetModulusSquare().Div(fAverageNoise)).Sum(size-1,1);
198 
199  fFilter1 *= size;
200  fFilter2 *= size;
201  QComplex null(0,0);
202  fFilter1[0] = null;
203  fFilter2[0] = null;
204 
205  int maxJitter = fMaxJitter;
206  int minJitter = -maxJitter;
207  for(int j = minJitter-EXTRA_JITTER; j <= maxJitter+EXTRA_JITTER; j++) {
208  QVector ap1Shifted = ap1;
209  ap1Shifted.Shift(j);
210  QVector ap2Shifted = ap2;
211  ap2Shifted.Shift(j);
212  QVectorC ap1ShiftedF,ap2ShiftedF;
213  fTransformer->TransformToFreq(ap1Shifted,ap1ShiftedF);
214  fTransformer->TransformToFreq(ap2Shifted,ap2ShiftedF);
215  fAveragePulse1Shifted.push_back(ap1ShiftedF);
216  fAveragePulse2Shifted.push_back(ap2ShiftedF);
217  fJitters.push_back(j);
218  }
219 }
220 
222 {
225 
227  double chi = fChiSquareWithJitter[fOptimumJitter];
228  for(int i = EXTRA_JITTER+1; i < int(fChiSquareWithJitter.size())-EXTRA_JITTER; i++) {
229  if(fChiSquareWithJitter[i] < chi) {
230  fOptimumJitter = i;
231  chi = fChiSquareWithJitter[i];
232  }
233  }
234  int index = fJitters[fOptimumJitter];
235  if(index < 0) index += fSize;
236  fAmplitude1 = fFiltered1[index];
237  fAmplitude2 = fFiltered2[index];
238  return err;
239 }
240 
241 
242 
243 vector<double> QBiComponentOptimumFilter::ChiSquare(const QVectorC& p, const QVector& ap1Filtered, const QVector& ap2Filtered) const
244 {
245  vector<double> chiSquare;
246  for(size_t j = 0; j < fJitters.size(); j++) {
247  double a1 = 0,a2= 0;
248  int jitter = fJitters[j];
249  if(jitter < 0) jitter += fSize;
250  a1 = ap1Filtered[jitter];
251  a2 = ap2Filtered[jitter];
252  const Diana::QVectorC& ap1f = fAveragePulse1Shifted[j];
253  const Diana::QVectorC& ap2f = fAveragePulse2Shifted[j];
254  double chi2 = (p-a1*ap1f-a2*ap2f).GetModulusSquare().Div(fAverageNoise).Sum(fSize-1,1);
255  chi2 /= (fSize-2);
256  chiSquare.push_back(chi2);
257  }
258  return chiSquare;
259 }
260 
261 
262 QVector QBiComponentOptimumFilter::GetFitFunction(const double jitter, const double a1, const double a2) const
263 {
264  QVector output = fAveragePulse1*a1+fAveragePulse2*a2;
265  output.ShiftReal(jitter);
266  return output;
267 }
268 
double diff
Definition: CheckOFShape.C:173
ap2
Definition: CheckOF.C:51
err
Definition: CheckOF.C:114
QVector an(N)
QVector vec(3)
#define EXTRA_JITTER
double Re(const Diana::QComplex &z)
Function to get the real part.
Definition: QComplex.cc:260
#define DianaThrow(obj)
Definition: QDianaDebug.hh:26
@ QERR_UNKNOWN_ERR
Definition: QError.hh:108
@ QERR_SIZE_NOT_MATCH
Definition: QError.hh:31
@ QERR_OUT_OF_RANGE
Definition: QError.hh:28
@ QERR_SUCCESS
Definition: QError.hh:27
Diana::QVector cos(const Diana::QVector &v)
Definition: QVector.cc:821
QError ComputeAmplitude(const Diana::QVectorC &transformed)
std::vector< double > ChiSquare(const Diana::QVectorC &p, const Diana::QVector &ap1Filtered, const Diana::QVector &ap2Filtered) const
Diana::QVector NormalizeVector(const Diana::QVector &vec) const
QError Filter(const Diana::QVector &p)
filter p. In case of failure an error is returned.
Diana::QVector GetFitFunction(const double jitter, const double a1, const double a2) const
std::vector< double > fChiSquareWithJitter
double GetChiSquareAtMinimium() const
get chi square value at its minimum, if Filter()!=QERR_SUCCESS throw the error
void BuildFilter(const Diana::QVector &ap1, const Diana::QVector &ap2)
QBiComponentOptimumFilter(const Diana::QVector &ap1, const Diana::QVector &ap2, const Diana::QVector &an, size_t maxJitter, bool diff=false)
constructor
int GetJitterAtMinimum() const
get jitter at the minimum of the chi square. if Filter()!=QERR_SUCCESS throw the error
const std::vector< double > & GetChiSquareWithJitter() const
get chi square as a function of jitter, same indexing of GetJitters(). if Filter()==QERR_SIZE_NOT_MAT...
QError GetInterpolated(double &jitter, double &a1, double &a2, double &integral) const
get values at interpolated chi^2 minimum. Three points around the minimum are used for a parabolic in...
void GetFiltered(Diana::QVector &f1, Diana::QVector &f2) const
get filtered waveforms. if Filter()==QERR_SIZE_NOT_MATCH throws the error
Diana::QRealComplexFFT * fTransformer
std::vector< Diana::QVectorC > fAveragePulse1Shifted
std::vector< Diana::QVectorC > fAveragePulse2Shifted
void GetAmplitude(double &a1, double &a2, double &integral) const
get amplitudes at chi^2 minimum. if Filter()!=QERR_SUCCESS throws the error
error class with error type and description
Definition: QError.hh:115
Wrapper for a specific QRealComplexFFT algorithm class.
the Diana namespace is needed because sometimes we use Qt libraries, that use same class names of our...