Diana Software
QOptimumFilter.cc
Go to the documentation of this file.
1 #include "QOptimumFilter.hh"
2 #include "QError.hh"
3 #include "QMatrix.hh"
4 #include "QRealComplexFFT.hh"
5 #include "QFir.hh"
6 #include "QVectorView.hh"
7 #include <sstream>
8 
9 // EXTRA_JITTERS:
10 // 1: minimum number needed for interpolation
11 // 2: more point to see if we have a minimum at the boundary (enable nice parabola)
12 
13 using std::vector;
14 using namespace Diana;
15 
16 QOptimumFilter::QOptimumFilter(const QVector& ap1, const QVector& an) :
17  fSize(0),
18  fMaxPos(0),
19  fMaxJitter(-1),
20  fDebugOn(false),
21  fUseDiff(true),
22  fTransformer(0),
23  fCutOffFrequency(Q_DOUBLE_DEFAULT)
24 {
26  fCheckForFilteredSamples.SetDescription(__FILE__,__LINE__,"Filtered samples not available");
27 
29  fCheckForBuiltFilter.SetDescription(__FILE__,__LINE__,"Filter not built");
30 
31  fSize = ap1.Size();
32 
33  QError err;
34  if(an.Size() != fSize) {
36  err.SetDescription(__FILE__,__LINE__,"Size of input QVectors mismatches");
37  DianaThrow(err);
38  }
40  fAveragePulse1 = ap1;
41  fAverageNoise = an;
42 }
43 
44 QOptimumFilter::QOptimumFilter(const QVector& ap1, const QVector& an, int maxJitter, bool useDiff, bool debugOn) : QOptimumFilter(ap1,an)
45 {
46  fMaxJitter = maxJitter;
47  fDebugOn = debugOn;
48  fUseDiff = useDiff;
49 
50 
53  if(err != QERR_SUCCESS) {DianaThrow(err);}
55  }
56 }
57 
58 
59 
60 
62 {
63  if(fTransformer) {
64  delete fTransformer;
65  fTransformer = 0;
66  }
67 }
68 
69 QError QOptimumFilter::Filter(const Diana::QVector& p)
70 {
72  fFiltered1.Clear();
73  if(p.Size() != fSize) {
74  QError err(QERR_SIZE_NOT_MATCH,__FILE__,__LINE__,"Size of input QVector is not correct");
77  }
78  if(fUseDiff) {
79  Diana::QVector diff = p;
80  diff.Differentiate();
81  fTransformer->TransformToFreq(diff,fTransformedWaveform);
82  } else {
83  fTransformer->TransformToFreq(p,fTransformedWaveform);
84  }
85  fTransformedWaveform[0].Set(0,0);
86  fTransformer->TransformFromFreq(fFilter1.Mult(fTransformedWaveform),fFiltered1);
87 
89 }
90 
91 const Diana::QVector& QOptimumFilter::GetFiltered() const
92 {
94  return fFiltered1;
95 }
96 
97 Diana::QVector QOptimumFilter::GetFilteredShifted() const
98 {
99  QVector filtShift = GetFiltered();
100  filtShift.Shift(fMaxPos);
101  return filtShift;
102 }
103 
104 
105 QError QOptimumFilter::GetInterpolated(double& intJitter, double& chi2,double& amplitude, double& integral, double& left, double& right) const
106 {
107  double dummy, yb,chib,leftb,rightb;
108  QError err = Get(dummy, chib, yb, dummy,leftb,rightb);
109  if(err != QERR_SUCCESS) return err;
110 
111  double xa = fOptimumJitter-1;
112  double xb = fOptimumJitter;
113  double xc = fOptimumJitter+1;
114 
115  int ia = fOptimumJitter-1; if(ia < 0) ia+=fSize;
116  double ya = fFiltered1[ia];
117 
118  int ic = fOptimumJitter+1; if(ic >= (int)fSize) ic-=fSize;
119  double yc = fFiltered1[ic];
120 
121  err = Parabola(xa,xb,xc,ya,yb,yc,amplitude,intJitter);
122  if(err != QERR_SUCCESS) return err;
123 
124  integral = fAvgPulseIntegral1*amplitude;
125 
126  // interpolate chi2
127  int low = floor(intJitter);
128  int dRLow,dRHigh;
129  int dLLow,dLHigh;
130  double chi1Low, chi1High;
131 
132  if(low == xa) {
133  const Diana::QVectorC& ap1fa = fAveragePulse1Shifted[ia];
134  double chia = (fTransformedWaveform-ya*ap1fa).GetModulusSquare().Div(fAverageNoiseForChi2).Sum(fSize-1,1);
135  chia /= (fSize-2);
136  chi1Low = chia;
137  chi1High = chib;
142 
143  } else {
144  const Diana::QVectorC& ap1fc = fAveragePulse1Shifted[ic];
145  double chic = (fTransformedWaveform-yc*ap1fc).GetModulusSquare().Div(fAverageNoiseForChi2).Sum(fSize-1,1);
146  chic /= (fSize-2);
147  chi1Low = chib;
148  chi1High = chic;
153  }
154 
155  double x = intJitter-low;
156 
157  chi2 = (chi1High-chi1Low)*x+chi1Low;
158 
159  right = (fFiltered1[dRHigh]-fFiltered1[dRLow])*x + fFiltered1[dRLow];
160  right = right/fFilteredAveragePulseHalfWidthValueRight-amplitude;
162 
163  left = (fFiltered1[dLHigh]-fFiltered1[dLLow])*x + fFiltered1[dLLow];
164  left = left/fFilteredAveragePulseHalfWidthValueLeft-amplitude;
166 
167  // left = leftb;
168  // right = rightb;
169 
170  if(intJitter > (int)fSize/2) intJitter-=fSize;
171 
172  return err;
173 }
174 
175 QVector QOptimumFilter::NormalizeVector(const QVector& vec) const
176 {
177  QVector ret = vec;
178  QVector baseline(ret.Size());
179  baseline.Initialize(ret[0]);
180  ret -= baseline;
181  ret /= ret.GetMax();
182  return ret;
183 }
184 
186 {
189  fMaxPos = fAveragePulse1.GetMaxIndex();
191 
192  // compute the time span from half-rise to maximum
194  double A = fAveragePulse1.GetMax()-fAveragePulse1[0];
195  for(int i = fMaxPos; i > 0; i--) {
196  if( (fAveragePulse1[i]-fAveragePulse1[0])<0.5*A ) {
198  break;
199  }
200  }
201 
202  if(fAvgPulseHalfTimeToMax < 1 || fAvgPulseHalfTimeToMax >= fMaxPos) {
204  err.SetDescription(__FILE__,__LINE__,"failed to autoset the maximum jitter");
205  return err;
206  }
207  // autoset maximum jitter
208 
210  if(fMaxJitter*2 > (int)fSize) {
212  err.SetDescription(__FILE__,__LINE__,"failed to autoset the maximum jitter");
213  return err;
214  }
215 
216  QVectorC apf; fTransformer->TransformToFreq(fAveragePulse1,apf);
217  fAveragePulseEnergySpectrum = apf.GetMagnitudesSquare();
218 
219  fAverageNoise[0] = 0;
220 
221  return err;
222 
223 }
224 
225 
226 
228 {
230  if(err != QERR_SUCCESS) return err;
231  fDebugVectors.clear();
232  fDebugSpectra.clear();
233 
234  QVector averageNoise = fAverageNoise;
235  QVector averagePulse = fAveragePulse1;
236 
237  if(fUseDiff) {
238  // differentiate noise and average pulse
239  double pi = M_PI;
240  for(size_t i = 0; i < fSize; i++){
241  if(i <= averageNoise.Size()/2) averageNoise[i] *= 2.*(1-cos(2.*pi/(averageNoise.Size())*i));
242  else averageNoise[i] *= 2.*(1-cos(2.*pi/(averageNoise.Size())*(averageNoise.Size()-i)));
243  }
244  averagePulse.Differentiate();
245  }
246 
247  // force to zero the average pulse at the boundaries
251  QVector ap = averagePulse.Mult(window);
252  QVectorC ap1f;
253  if(fDebugOn) {
254  fTransformer->TransformToFreq(averagePulse,ap1f);
255  fDebugSpectra.push_back(averageNoise); // 0 input average noise
256  fDebugSpectra.push_back(ap1f.GetMagnitudesSquare()); // 1 average pulse
257  fDebugVectors.push_back(ap); // 0 windowed average pulse
258  }
259 
260  // create filter in FD
261  QVectorC anc(fSize);
262  anc.Initialize(0,0);
263  anc.SetRe(averageNoise);
264  fTransformer->TransformToFreq(ap,ap1f);
265  QVector SNR = ap1f.GetModulusSquare().Div(averageNoise);
266  double M = 1./SNR.Sum(fSize-1,1);
267  fFilter1 = M*ap1f.Conj().Div(anc);
268  fFilter1 *= fSize;
269  fFilter1[0].Set(0,0);
270 
271  // get kernel in TD
272  QVector kernel;
273  fTransformer->TransformFromFreq(fFilter1,kernel);
274  if(fDebugOn) {
275  fDebugSpectra.push_back(ap1f.GetMagnitudesSquare()); // 2 windowed average pulse
276  fDebugSpectra.push_back(fFilter1.GetMagnitudesSquare()); // 3 filter in FD with windowed average pulse
277  fDebugVectors.push_back(kernel); // 1 filter in TD with windowed average pulse
278  }
279 
280 
281  // determine SNR as a function of frequency
282  fSNRFreq.Resize(fSize/2+1); fSNRFreq[0] = 0;
283  for(size_t i = 1; i < fSize/2; i++) {
284  fSNRFreq[i] = fSNRFreq[i-1]+2*SNR[i];
285  }
286  fSNRFreq[fSize/2] = fSNRFreq[fSize/2-1]+SNR[fSize/2];
287  if(fDebugOn) {
288  QVector filteredAverageNoise = fFilter1.GetModulusSquare().Mult(averageNoise);
289  fDebugSpectra.push_back(filteredAverageNoise); // 4 filtered average noise with windowed average pulse
290  }
291  // filter out frequencies where SNR improvement is irrelevant
292  size_t cutOffFrequency = fSize/2;
293  for( ; cutOffFrequency > 1; cutOffFrequency--) {
294  if(fSNRFreq[cutOffFrequency] < 0.990*fSNRFreq[fSize/2]) break;
295  }
296  fCutOffFrequency = double(cutOffFrequency)/fSize; // normalize to Nyquist
297 
298  fSNRNorm.Resize(fSize/2+1);
299  fSNRNorm.Initialize(0);
300  for(size_t i = 1; i < cutOffFrequency; i++) fSNRNorm[i] = SNR[i];
301  fSNRNorm = fSNRNorm / fSNRNorm.GetMax();
302 
303 
304 
305  QCFirData firData;
307  firData.fCutoff= fCutOffFrequency;
308  firData.fM= fMaxJitter*2;
309  if(firData.fM%2 == 0) firData.fM--;
310  firData.fAttDB= 60;
311  QFir fir(firData);
312  int reduction = fir.GetFilterReduction();
313  QVector kernelout;
314  fir.Filter(kernel,kernelout);
315  for(size_t i = reduction/2; i < fSize-reduction/2; i++) kernel[i]=kernelout[i-reduction/2];
316  if(fDebugOn) {
317  fDebugVectors.push_back(kernel); // 2 filter in TD low-pass filtered
318  }
319 
320 
321  // force to zero the kernel at the boundaries
324  fValidSample.resize(fSize);
325  for(size_t i = 0; i < fSize; i++) {
326  kernel[i] *= window2[i];
327  // store the information on the samples that are correctly filtered
328  fValidSample[i] = (window2[i] == 0);
329  }
330 
331  // force to zero the integral of the survived kernel
332  double integral = kernel.Sum(fSize,0);
333 
334  // alternate method
335  /*
336  double add = integral/fEffectiveFilterLength;
337  add *= fEffectiveFilterLength/window2.Sum(fSize,0);
338  for(size_t i = 0; i < fSize; i++) {
339  kernel[i] -= add*window2[i];
340  }
341  */
342 
343  double add = 0;
344  for(size_t i = 0; i < fSize; i++) {
345  if(kernel[i] < 0) add += kernel[i];
346  }
347  for(size_t i = 0; i < fSize; i++) {
348  if(!fValidSample[i]) {
349  if(integral > 0 && kernel[i] < 0) kernel[i] *= (add-integral)/add;
350  else if(integral < 0 && kernel[i] > 0) kernel[i] *= add/(add-integral);
351  }
352  }
353 
354 
355  fTransformer->TransformToFreq(kernel,fFilter1);
356 
357  // force to zero the filter integral (even if it should be aready zero)
358  // fFilter1[0].Set(0.,0.);
359  fFilter1[fSize/2].SetIm(0.);
360 
361 
362  // Adjust gain since we manipulated the kernel
364  if(err != QERR_SUCCESS) return err;
365 
366  fFilter1 /= fFiltered1[0];
368  if(err != QERR_SUCCESS) return err;
369 
370  // Compute half width of the AP
372  for(size_t i = 0; i < fSize/2; i++) {
373  if(fFiltered1[i] < 0.5*fFiltered1.GetMax()) {
374  // fFilteredAveragePulseHalfWidth=i-1 + (0.5-fFiltered1[i-1])/(fFiltered1[i]-fFiltered1[i-1]);
378  break;
379  }
380  }
381 
382 
383 
384  // Store filter in TD
385  fTransformer->TransformFromFreq(fFilter1,fFilterTD);
386 
387  // estimate filtered average noise and resolution
388  fFilteredAverageNoise = fFilter1.GetModulusSquare().Mult(averageNoise);
390 
391  QVector autoCorrelation;
392  QVectorC noiseC(fSize);
393  noiseC.Initialize(0);
394  noiseC.SetRe(fFilteredAverageNoise);
395  fTransformer->TransformFromFreq(noiseC,autoCorrelation);
396 
397  fFilteredRMS1 = sqrt(autoCorrelation[0]/fSize);
398  fFilteredAutoCorrelation = sqrt(autoCorrelation[lround(fFilteredAveragePulseHalfWidth)]/fSize);
399 
400 
401 
402 
403  // estimate shifted ap spectra for chi2 evaluation
404  //
405  fAverageNoiseForChi2=averageNoise;
407  for(size_t j = 0; j < fSize; j++) {
408  if(fValidSample[j]) {
409  QVector ap1Shifted;
410  if(fAveragePulse1Shifted[j].Size() == 0) {
411  ap1Shifted = averagePulse;
412  ap1Shifted.Shift(j);
413  fTransformer->TransformToFreq(ap1Shifted,fAveragePulse1Shifted[j]);
414  }
415  if(j+1 < fSize && fAveragePulse1Shifted[j+1].Size() == 0) {
416  ap1Shifted = averagePulse;
417  ap1Shifted.Shift(j+1);
418  fTransformer->TransformToFreq(ap1Shifted,fAveragePulse1Shifted[j+1]);
419  }
420  if(j > 0 && fAveragePulse1Shifted[j-1].Size() == 0) {
421  ap1Shifted = averagePulse;
422  ap1Shifted.Shift(j-1);
423  fTransformer->TransformToFreq(ap1Shifted,fAveragePulse1Shifted[j-1]);
424  }
425 
426  }
427  }
428 
429  /*
430  // check with a signal with SNR = 1000;
431  err = Filter(fAveragePulse1*1000);
432  if(err != QERR_SUCCESS) return err;
433  double jitter,chi2,amplitude,integralo,left,right;
434  fOptimumJitter = 0;
435  GetInterpolated(jitter,chi2,amplitude,integralo,left,right);
436  std::cout<<"jitter: "<<jitter<<" chi2: "<<chi2<<" amplitude: "<<amplitude<<" integral: "<<integralo<<" left: "<<left<<" right: "<<right<<std::endl;
437  */
438 
440  fCheckForFilteredSamples.SetDescription(__FILE__,__LINE__,"Filtered samples not available");
441 
442  return err;
443 
444 }
445 
447 {
450  switch(mode) {
451  case J_ABSMAX:
452  fOptimumJitter = fFiltered1.GetMaxIndex();
453  break;
454  case J_LOCMAX:
455  {
456  size_t searchinterval=5*fFilteredAveragePulseHalfWidth;
457  if(searchinterval>fFiltered1.Size()/2){
458  searchinterval=fFiltered1.Size()/2;
459  }
460  if(searchinterval == 0) searchinterval = 1;
461  //Before
462  size_t beforemax = fFiltered1.GetSubVector(searchinterval,fFiltered1.Size()-searchinterval).GetMaxIndex();
463  beforemax += fFiltered1.Size()-searchinterval;
464  //After
465  size_t aftermax = fFiltered1.GetSubVector(searchinterval).GetMaxIndex();
466 
467  //Compare
468  fOptimumJitter=aftermax;
469  if(fFiltered1[beforemax]>fFiltered1[aftermax]){
470  fOptimumJitter=beforemax;
471  }
472 
473  }
474 
475  break;
476  case J_FIXED:
477  if(triggerpos < 0) triggerpos += fSize;
478  if(triggerpos < (int)fSize)
479  fOptimumJitter = triggerpos;
480  else {
482  err.SetDescription(__FILE__,__LINE__,"Fixed jitter provided is out of range");
483  }
484  break;
485  case J_NOJITTER:
486  fOptimumJitter = 0;
487  break;
488  default:
490  err.SetDescription(__FILE__,__LINE__,"Jitter mode not implemented");
491 
492  }
493  if(err != QERR_SUCCESS) return err;
494 
497  std::stringstream msg;
498  msg<<"Maximum position "<<fOptimumJitter<<" lies outside the filter effective length";
499  err.SetDescription(__FILE__,__LINE__,msg.str());
500  //std::cout<<"Maximum was: "<<fFiltered1.GetMaxIndex()<<" TriggerPos: "<<triggerpos-fMaxPos<<std::endl;
501  }
502  return err;
503 
504 }
505 
506 QError QOptimumFilter::Get(double& jitter, double& chi2, double& amplitude, double& integral, double& left, double& right) const
507 {
510 
511  jitter = fOptimumJitter;
512  if(fOptimumJitter > (int)fSize/2) jitter-=fSize;
513  amplitude = fFiltered1[fOptimumJitter];
514  integral = fAvgPulseIntegral1*amplitude;
515 
516  const Diana::QVectorC& ap1f = fAveragePulse1Shifted[fOptimumJitter];
517  QVector residuals = (fTransformedWaveform-amplitude*ap1f).GetModulusSquare().Div(fAverageNoiseForChi2);
518  chi2 = residuals.Sum(fSize-1,1)/(fSize-2);
519 
520  int derivativeMaxPos = (fOptimumJitter-fFilteredAveragePulseHalfWidth+fSize)%fSize;
521  left = fFiltered1[derivativeMaxPos]/fFilteredAveragePulseHalfWidthValueLeft-amplitude;
523 
524  int derivativeMinPos = (fOptimumJitter+fFilteredAveragePulseHalfWidth+fSize)%fSize;
525  right = fFiltered1[derivativeMinPos]/fFilteredAveragePulseHalfWidthValueRight-amplitude;
527 
528 
529  return err;
530 }
531 
532 QError QOptimumFilter::GetHighSNRChi2(const double& threshold, double& chi2) const
533 {
536 
537  const double amplitude = fFiltered1[fOptimumJitter];
538  const Diana::QVectorC& ap1f = fAveragePulse1Shifted[fOptimumJitter];
539 
540  QVector residuals = (fTransformedWaveform-amplitude*ap1f).GetModulusSquare().Div(fAverageNoiseForChi2);
541 
542  chi2 = 0;
543  int dof = -1; // we fitted for the amplitude
544  for(size_t i = 1; i < fSNRNorm.Size(); i++) {
545  if(fSNRNorm[i] > threshold) {
546  chi2 += residuals[i];
547  dof++;
548  }
549  }
550  if(dof < 1) {
552  err.SetDescription(__FILE__,__LINE__,"Number of degrees of freedom is < 1");
553  return err;
554  }
555 
556  // make it zero mean and unit variance for easy cuts
557  chi2 -= dof;
558  chi2 /= sqrt(2*dof);
559  return err;
560 
561 }
562 
563 
564 std::vector<double> QOptimumFilter::Get() const
565 {
566  std::vector<double> results;
568  exit(-1);
569  }
570  results.push_back(fOptimumJitter);
571  // double jitter = fOptimumJitter;
572  // if(fOptimumJitter > (int)fSize/2) jitter-=fSize;
573  double amplitude = fFiltered1[fOptimumJitter];
574  results.push_back(fFiltered1[fOptimumJitter]);
575  // std::cout<<fOptimumJitter<<" "<<fAmplitude1<<std::endl;
576  const Diana::QVectorC& ap1f = fAveragePulse1Shifted[fOptimumJitter];
577  double chi2 = (fTransformedWaveform-amplitude*ap1f).GetModulusSquare().Div(fAverageNoiseForChi2).Sum(fSize-1,1);
578  chi2 /= (fSize-2);
579  results.push_back(chi2);
580  results.push_back( fAvgPulseIntegral1*amplitude);
581 
582  return results;
583 }
584 
585 QVector QOptimumFilter::GetFitFunction(const double jitter, const double a1) const
586 {
587  QVector output = fAveragePulse1*a1;
588  output.ShiftReal(jitter);
589  return output;
590 }
591 
592 
593 QError QOptimumFilter::Parabola(double xa,double xb, double xc, double ya,double yb, double yc,double &max, double& maxPos) const
594 {
596  if(yb<ya || yb<yc) {
598  std::stringstream msg;
599  msg<<"y "<<yb<<" not at maximum. Boundaries: ["<<ya<<" "<<yc<<"]";
600  err.SetDescription(__FILE__,__LINE__,msg.str());
601  return err;
602  }
603 
604  double detA = xa*xa*(xb-xc)-xb*xb*(xa-xc)+xc*xc*(xa-xb);
605  double detA1 = ya*(xb-xc)-yb*(xa-xc)+yc*(xa-xb);
606  double detA2 = xa*xa*(yb-yc)-xb*xb*(ya-yc)+xc*xc*(ya-yb);
607  double detA3 = xa*xa*(xb*yc-yb*xc)-xb*xb*(xa*yc-ya*xc)+xc*xc*(xa*yb-ya*xb);
608 
609  double p0 = detA1/detA;
610  double p1 = detA2/detA;
611  double p2 = detA3/detA;
612 
613  max = -p1*p1/(4.*p0)+p2;
614  maxPos = -p1/2./p0;
615 
616  if(maxPos <xa || maxPos >xc) {
618  std::stringstream msg;
619  msg<<"Interpolated position "<<maxPos<<" out of boundaries ["<<xa<<" "<<xc<<"]";
620  err.SetDescription(__FILE__,__LINE__,msg.str());
621  return err;
622  }
623  return err;
624 }
625 
double diff
Definition: CheckOFShape.C:173
ap
Definition: CheckOFShape.C:47
double max
Definition: CheckOF.C:53
err
Definition: CheckOF.C:114
QVector an(N)
QVector vec(3)
Diana::QComplex pow(const Diana::QComplex &z, double a)
Raise a complex number to a real power.
Definition: QComplex.cc:246
#define DianaThrow(obj)
Definition: QDianaDebug.hh:26
#define Q_DOUBLE_DEFAULT
Definition: QDiana.hh:24
@ 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
Data class for QFir (Ported from Calder)
Definition: QCFirData.hh:14
Method fMethod
Definition: QCFirData.hh:34
double fCutoff
Definition: QCFirData.hh:36
@ KayserBessel
Definition: QCFirData.hh:18
double fAttDB
Definition: QCFirData.hh:37
error class with error type and description
Definition: QError.hh:115
void SetDescription(const std::string &descr)
set error description
Definition: QError.hh:147
@ WT_Cosinus
Definition: QFFT.hh:36
static QVector ZeroPad(const QVector &input, size_t n_zeros, int Side=kMiddle, double zeroVal=0.)
Add zeros to the input.
Definition: QFFT.cc:216
static QVector GetWindow(WindowType wt, size_t size, size_t zeros=0, int coherent=0, int param=0)
create window and add zeros/2 to the left and zeros/2 to the right
Definition: QFFT.cc:82
@ kSymmetric
Definition: QFFT.hh:42
QFir FIR low pass filter (Ported from Calder)
Definition: QFir.hh:17
QError Filter(const Diana::QVector &input, Diana::QVector &output) const
Definition: QFir.cc:63
size_t GetFilterReduction() const
Definition: QFir.hh:25
Optimum filter implemented with windowing and zeros.
Diana::QVector fAverageNoiseForChi2
QError GetInterpolated(double &jitter, double &chi2, double &amplitude, double &integral, double &left, double &right) const
get values at interpolated chi^2 minimum. Three points around the minimum are used for a parabolic in...
QError fCheckForFilteredSamples
Diana::QVector NormalizeVector(const Diana::QVector &vec) const
std::vector< Diana::QVector > fDebugSpectra
std::vector< Diana::QVector > fDebugVectors
QError Parabola(double xa, double xb, double xc, double ya, double yb, double yc, double &min, double &minpos) const
QError GetHighSNRChi2(const double &threshold, double &chi2) const
get chi^2 (mean 0, variance 1) restricting the DoF to frequencies with SNR > threshold
virtual ~QOptimumFilter()
Diana::QVector fAveragePulseEnergySpectrum
Diana::QRealComplexFFT * fTransformer
Diana::QVector fFilterTD
Diana::QVector GetFilteredShifted() const
get filtered and shifted samples by fMaxPos
int fFilteredAveragePulseHalfWidth
Diana::QVector GetFitFunction(const double jitter, const double a1) const
Diana::QVector fSNRFreq
Diana::QVector fFiltered1
double fFilteredAveragePulseHalfWidthValueLeft
size_t fEffectiveFilterLength
Diana::QVector fSNRNorm
Diana::QVectorC fFilter1
Diana::QVectorC fTransformedWaveform
QError fCheckForBuiltFilter
double fAvgPulseIntegral1
virtual QError ManipulateInputs()
QError SetJitter(JitterMode mode, int start=0)
Diana::QVector fAveragePulse1
QOptimumFilter(const Diana::QVector &ap1, const Diana::QVector &an, int maxJitter, bool useDiff=false, bool debugOn=false)
constructor
std::vector< Diana::QVectorC > fAveragePulse1Shifted
std::vector< bool > fValidSample
Diana::QVector fAverageNoise
std::vector< double > Get() const
const Diana::QVector & GetFiltered() const
get filtered samples
double fFilteredAveragePulseHalfWidthValueRight
QError Filter(const Diana::QVector &p)
filter. In case of failure an error is returned.
Diana::QVector fFilteredAverageNoise
QError BuildFilter()
double fFilteredAutoCorrelation
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...