SystemResponse.cc
1 #include "SystemResponse.h"
2 #include "FFTtools.h"
3 #include "TF1.h"
4 
5 #include "AnalysisWaveform.h"
6 
7 
8 static AnitaResponse::BandLimitedDeconvolution bld(0.18,1.1);
9 AnitaResponse::DeconvolutionMethod & AnitaResponse::kDefaultDeconvolution = bld;
10 
11 
12 void AnitaResponse::DeconvolutionMethod::deconvolve(int Nf, double df, FFTWComplex * Y, const FFTWComplex * response) const
13 {
14  AnalysisWaveform wf(2*(Nf-1),Y, df,0);
15  AnalysisWaveform r(2*(Nf-1),response, df,0);
16  deconvolve(&wf,&r);
17 
18 }
19 
20 void AnitaResponse::WienerDeconvolution::deconvolve(AnalysisWaveform *wf, const AnalysisWaveform * response_wf) const
21 {
22 
23  size_t N = wf->Nfreq();
24  double df = wf->deltaF();
25  FFTWComplex * Y = wf->updateFreq();
26 
27  const FFTWComplex * response = response_wf->freq();
28 
29 
30  FFTWComplex zero(0,0);
31  for (unsigned i = 0; i < N; i++)
32  {
33  double f = i * df;
34 
35  double H2 = response[i].getAbsSq();
36  double SNR = snr(f,H2,N);
37  printf("SNR(%f) = %f\n", f, SNR);
38 
39  if (SNR <=0) Y[i] = zero;
40  else
41  {
42  Y[i] = Y[i] / response[i] * ( H2 / (H2 + 1./SNR));
43  }
44  }
45 }
46 
47 
48 AnitaResponse::WienerDeconvolution::WienerDeconvolution(const TGraph *g, const double * sc)
49 {
50  snr_graph = g;
51  min = g->GetX()[0];
52  max = g->GetX()[g->GetN()-1];
53  snr_function = 0;
54  noise_level = 0;
55  scale = sc;
56 }
57 
59 {
60  snr_function = f;
61  noise_level = 0;
62  f->GetRange(min,max);
63  snr_graph = 0;
64  scale = 0;
65 }
66 
68 {
69  snr_graph = 0;
70  scale = 0;
71  snr_function = 0;
72  noise_level = N;
73 }
74 
75 
76 
77 double AnitaResponse::WienerDeconvolution::snr(double f, double R2, int N ) const
78 {
79 
80 
81  if (snr_graph)
82  {
83  if (f < min || f > max ) return 0;
84  double sc = scale ? *scale : 1;
85  return sc*snr_graph->Eval(f);
86  }
87  else if (snr_function)
88  {
89 // printf("%f\n",f);
90  if (f < min || f > max ) return 0;
91  return snr_function->Eval(f);
92  }
93  else if (noise_level)
94  {
95 // printf("%g %g\n",R2,noise_level);
96  return R2/noise_level/N ;
97  }
98 
99  fprintf(stderr,"Something's wrong...\n");
100 
101  return -1;
102 }
103 
104 void AnitaResponse::AllPassDeconvolution::deconvolve(AnalysisWaveform * wf, const AnalysisWaveform * response_wf) const
105 {
106 
107  size_t N = wf->Nfreq();
108  FFTWComplex * Y = wf->updateFreq();
109  const FFTWComplex * response = response_wf->freq();
110 
111  for (unsigned i = 0; i < N; i++)
112  {
113  FFTWComplex r = response[i];
114  r/= r.getAbs();
115  Y[i]/=r;
116  }
117 }
118 
119 void AnitaResponse::ImpulseResponseXCorr::deconvolve(AnalysisWaveform * wf, const AnalysisWaveform * response_wf) const
120 {
121 
122  size_t N = wf->Nfreq();
123  FFTWComplex * Y = wf->updateFreq();
124  const FFTWComplex * response = response_wf->freq();
125  double total_mag = 0;
126  for (unsigned i = 0; i < N; i++)
127  {
128  total_mag += response[i].getAbsSq();
129  }
130  total_mag = sqrt(total_mag);
131 
132  for (unsigned i = 0; i < N; i++)
133  {
134  FFTWComplex r = response[i].conj();
135  Y[i]*=r/total_mag;
136  }
137 }
138 
139 AnitaResponse::CLEAN::CLEAN(int max_loops, double loop_gain, double thresh_factor, TString restoring_beam, bool add_residuals, bool only_return_residuals)
140 {
141  fMaxLoops = max_loops;
142  fLoopGain = loop_gain;
143  fThreshFactor = thresh_factor;
144  fRestoringBeam = restoring_beam;
145  fAddResiduals = add_residuals;
146  fOnlyReturnResiduals = only_return_residuals;
147 }
148 
149 void AnitaResponse::CLEAN::deconvolve(AnalysisWaveform * Y, const AnalysisWaveform * resp) const
150 {
151  //set up analysis waveforms
152  AnalysisWaveform clean(*Y);
153  for(int i = 0; i < clean.even()->GetN(); i++)
154  {
155  clean.updateEven()->GetY()[i] = 0;
156  }
157  AnalysisWaveform y(*Y);
158  AnalysisWaveform rbeam(*Y);
159  AnalysisWaveform r(*resp);
160  AnalysisWaveform* xc = 0;
161 
162  //set up hyperparameters
163  double noise_est=0;
164  double noise_mean=0;
165  double n_noise=0;
166  for(int i = 0; i < y.Neven(); i++)
167  {
168  if(y.even()->GetX()[i] < 25 || y.even()->GetX()[i] > 70)
169  {
170  noise_est += y.even()->GetY()[i] * y.even()->GetY()[i];
171  noise_mean += y.even()->GetY()[i];
172  n_noise++;
173  }
174  }
175  noise_mean /= n_noise;
176  noise_est = sqrt(noise_est/n_noise - (noise_mean * noise_mean));
177  //double noise_est = TMath::RMS(y.Neven(), y.even()->GetY());
178  double snr_est = (1./fThreshFactor) * (y.even()->pk2pk())/(2*noise_est);
179  //printf("snr est = %g, rms = %g, nt1 = %d, vpp = %g\n", snr_est, noise_est, n_noise, y.even()->pk2pk());
180 
181  double thresh = 1./snr_est;
182  double loop_gain = fLoopGain;
183  int max_loops = fMaxLoops;
184  double noise_level = snr_est/3.;
185  double max_corr = 0;
186  double max_clean = 0;
187 
188  //rescale template to WF
189  double max_y = y.even()->peakVal(0, 0, -1, true);
190  double max_r = r.even()->peakVal(0, 0, -1, true);
191 
192  double scale_to_wf = (TMath::Abs(max_y))/(TMath::Abs(max_r));
193 
194  for(int i = 0; i < r.Neven(); i++)
195  {
196  r.updateEven()->GetY()[i] *= scale_to_wf;
197  }
198 
199  //rescale
200  double normalize = 1./sqrt(y.even()->getSumV2() + r.even()->getSumV2());
201  for(int i = 0; i < y.Neven(); i++)
202  {
203  y.updateEven()->GetY()[i] *= normalize;
204  }
205  for(int i = 0; i < r.Neven(); i++)
206  {
207  r.updateEven()->GetY()[i] *= normalize;
208  }
209  if(fRestoringBeam.Length() > 0)
210  {
211  TF1 restore("restoring_beam", fRestoringBeam.Data(), y.even()->GetX()[0], y.even()->GetX()[y.Neven()-1]);
212  for(int i = 0; i < rbeam.Neven(); i++)
213  {
214  rbeam.updateEven()->GetY()[i] = restore.Eval(rbeam.updateEven()->GetX()[i]);
215  }
216 
217  //normalize to unit sum
218  double restore_norm = rbeam.even()->getSumV2();
219  for(int i = 0; i < rbeam.Neven(); i++)
220  {
221  rbeam.updateEven()->GetY()[i] /= restore_norm;
222  }
223  }
224 
225  //shift response to middle for ease
226  int loc = TMath::LocMax(r.Neven(), r.even()->GetY());
227  r.updateEven()->shift(r.Neven()/2 - loc, false);
228  double E_i = y.even()->getSumV2();
229  double E_curr = E_i;
230 
231  //start CLEANING
232  while(((E_curr/E_i) > thresh) && (max_loops != 0))
233  {
234  max_loops--;
235  double rms1 = y.even()->GetRMS(2);
236  double rms2 = r.even()->GetRMS(2);
237  xc = AnalysisWaveform::correlation(&y, &r, 0, rms1 * rms2);
238  max_corr = xc->even()->peakVal(&loc, 0, -1, true);
239  clean.updateEven()->GetY()[loc] += xc->even()->GetY()[loc] * loop_gain;
240  //shift template to align with peak of correlation
241  r.updateEven()->shift(xc->Neven()/2 - loc, false);
242  //subtract impulse response from dirty waveform
243  for(int i = 0; i < y.even()->GetN(); i++)
244  {
245  y.updateEven()->GetY()[i] -= loop_gain * r.even()->GetY()[i] * xc->even()->GetY()[loc];
246  }
247  r.updateEven()->shift(-1*(xc->Neven()/2 - loc), false);
248  E_curr = y.even()->getSumV2();
249  delete xc;
250  }
251  max_clean = clean.even()->peakVal(0, 0, -1, true);
252  //rescale back up residuals and remove clean components below the noise floor or rescale back up ones that are above
253  for(int i = 0; i < y.Neven(); i++)
254  {
255  y.updateEven()->GetY()[i] *= 1./normalize;
256  clean.updateEven()->GetY()[i] *= (fabs(clean.updateEven()->GetY()[i]) > max_clean/noise_level) ? 1./normalize : 0;
257  }
258  if(fOnlyReturnResiduals)
259  {
260  for(int i = 0; i < Y->Nfreq(); i++)
261  {
262  Y->updateFreq()[i] = y.freq()[i];
263  }
264  }
265  else if(fRestoringBeam.Length() > 0)
266  {
267  //convolve clean components w/ restoring beam
268  //xc = AnalysisWaveform::convolution(&rbeam, &clean);
269  //xc->even()->peakVal(&loc, 0, -1, true);
270  //xc->updateEven()->shift(xc->Neven()/2 - loc, false);
271  xc = new AnalysisWaveform(clean.Neven(), clean.freq(), clean.deltaF(), clean.even()->GetX()[0]);
272  for(int i = 0; i < xc->Nfreq(); i++)
273  {
274  xc->updateFreq()[i] *= rbeam.freq()[i];
275  }
276  double scale_clean = fabs(clean.even()->peakVal(0, 0, -1, 1)/xc->even()->peakVal(0,0,-1,1));
277  for(int i = 0; i < xc->Neven(); i++)
278  {
279  xc->updateEven()->GetY()[i] *= scale_clean;
280  }
281  //add back residuals
282  if(fAddResiduals)
283  {
284  for(int i = 0; i < xc->Neven(); i++)
285  {
286  xc->updateEven()->GetY()[i] += y.even()->GetY()[i];
287  }
288  }
289  //return the cleaned stuff
290  for(int i = 0; i < Y->Nfreq(); i++)
291  {
292  Y->updateFreq()[i] = xc->freq()[i];
293  }
294  delete xc;
295  }
296  else
297  {
298  if(fAddResiduals)
299  {
300  for(int i = 0; i < clean.Neven(); i++)
301  {
302  clean.updateEven()->GetY()[i] += y.even()->GetY()[i];
303  }
304  }
305  //return the cleaned stuff
306  for(int i = 0; i < Y->Nfreq(); i++)
307  {
308  Y->updateFreq()[i] = clean.freq()[i];
309  }
310  }
311 }
312 
313 void AnitaResponse::NaiveDeconvolution::deconvolve(AnalysisWaveform * wf, const AnalysisWaveform * response_wf) const
314 {
315 
316  size_t N = wf->Nfreq();
317  FFTWComplex * Y = wf->updateFreq();
318  const FFTWComplex * response = response_wf->freq();
319 
320  for (unsigned i = 0; i < N; i++)
321  {
322  Y[i]/=response[i];
323  }
324 }
325 
326 void AnitaResponse::BandLimitedDeconvolution::deconvolve(AnalysisWaveform * wf, const AnalysisWaveform * response_wf) const
327 {
328 
329  size_t N = wf->Nfreq();
330  FFTWComplex * Y = wf->updateFreq();
331  double df = wf->deltaF();
332  const FFTWComplex * response = response_wf->freq();
333 
334  size_t min_i =(size_t) TMath::Max(0,int(min_freq / df));
335  size_t max_i =(size_t) TMath::Min((int) N-1, int(max_freq / df));
336  FFTWComplex zero(0,0);
337 
338  for (size_t i = 0; i < min_i; i++)
339  {
340  Y[i] = zero;
341  }
342 
343  for (size_t i = min_i; i < max_i; i++)
344  {
345  Y[i]/=response[i];
346  }
347  for (size_t i = max_i; i < N; i++)
348  {
349  Y[i] = zero;
350  }
351 
352 }
353 
354 
355 
356 AnitaResponse::Response::Response(int Nfreq, double df, int nangles, const double * the_angles, const FFTWComplex ** the_responses)
357  : Nfreq(Nfreq), df(df)
358 {
359  for (int i = 0; i < nangles; i++)
360  {
361  addResponseAtAngle(the_angles[i], the_responses[i]);
362  }
363 
364 }
365 
366 void AnitaResponse::Response::addResponseAtAngle(double angle, const FFTWComplex * response)
367 {
368  FFTWComplex * copy = new FFTWComplex[Nfreq];
369  memcpy(copy, response, Nfreq * sizeof(FFTWComplex));
370  responses[angle] = copy;
371 // if (angle == 0) response_at_zero = copy;
372  dirty = true;
373 }
374 
375 AnitaResponse::Response::Response(int Nfreq, double df)
376  : Nfreq(Nfreq), df(df)
377 {
378 
379 }
380 
381 AnitaResponse::Response::Response(const TGraph * timedomain, int npad)
382 {
383  AnalysisWaveform aw(timedomain->GetN(), timedomain->GetX(), timedomain->GetY(), timedomain->GetX()[1] - timedomain->GetX()[0]);
384  aw.padEven(npad);
385  (void) aw.freq();
386  df = aw.deltaF();
387  Nfreq = aw.Nfreq();
388  addResponseAtAngle(0,aw.freq());
389 }
390 
391 
392 
393 AnitaResponse::Response::Response(int Nfreq, double df, const FFTWComplex * response)
394  : Nfreq(Nfreq),df(df)
395 {
396  addResponseAtAngle(0, response);
397 }
398 
399 
400 FFTWComplex * AnitaResponse::AbstractResponse::getResponseArray(int N, const double * f, double angle, FFTWComplex *answer) const
401 {
402  if (!answer) answer = new FFTWComplex[N];
403  for (int i = 0; i < N; i++) answer[i] = getResponse(f[i], angle);
404  return answer;
405 
406 }
407 
408 FFTWComplex * AnitaResponse::AbstractResponse::getResponseArray(int N, double df, double angle, FFTWComplex *answer) const
409 {
410  if (!answer) answer = new FFTWComplex[N];
411  for (int i = 0; i < N; i++) answer[i] = getResponse(i*df, angle);
412  return answer;
413 }
414 
415 
416 
417 void AnitaResponse::Response::recompute() const
418 {
419 
420  int nangles = responses.size();
421  real.SetBins( Nfreq, 0, df * Nfreq,nangles, -90, 90);
422  imag.SetBins( Nfreq, 0, df * Nfreq, nangles, -90, 90);
423 
424 
425 
426  if (nangles > 1)
427  {
428  double bin_boundaries[nangles+1];
429  double center_angles[nangles];
430 
431  //fill in centers of angles
432  int i = 0;
433  for (std::map<double, FFTWComplex *>::const_iterator it = responses.begin(); it!=responses.end(); it++)
434  {
435  center_angles[i++] = it->first;
436  }
437 
438 
439  bin_boundaries[0] = center_angles[0] - (center_angles[1]-center_angles[0])/2;
440  bin_boundaries[nangles] = center_angles[nangles-1] + (center_angles[nangles-1]-center_angles[nangles-2])/2;
441 
442  for (int i = 1; i < nangles; i++)
443  {
444  bin_boundaries[i] = (center_angles[i-1] + center_angles[i])/2;
445  }
446 
447  imag.GetYaxis()->Set(nangles, bin_boundaries);
448  real.GetYaxis()->Set(nangles, bin_boundaries);
449  }
450 
451  int j = 1;
452 
453  for (std::map<double, FFTWComplex *>::const_iterator it = responses.begin(); it!=responses.end(); it++)
454  {
455  for (int i = 0; i < Nfreq; i++)
456  {
457  imag.SetBinContent(i+1,j, it->second[i].im);
458  real.SetBinContent(i+1,j, it->second[i].re);
459  }
460  j++;
461  }
462 
463 // imag.Print();
464 
465  dirty = false;
466 }
467 
468 FFTWComplex AnitaResponse::CompositeResponse::getResponse(double f, double angle ) const
469 {
470 
471  FFTWComplex answer(1,0);
472  for (size_t i = 0; i < responses.size(); i++) answer*= responses[i]->getResponse(f,angle);
473  return answer;
474 }
475 
476 
477 
478 
479 
480 
481 FFTWComplex AnitaResponse::Response::getResponse(double f, double angle ) const
482 {
483  lock.Lock();
484  if (dirty)
485  {
486  recompute();
487  }
488  lock.UnLock();
489 
490 // printf("%f %f %f %f %f %f\n", f, angle, real.GetXaxis()->GetXmin(), real.GetXaxis()->GetXmax(), real.GetYaxis()->GetXmin(), real.GetYaxis()->GetXmax());
491  if ( f > real.GetXaxis()->GetXmax() || f > imag.GetXaxis()->GetXmax()) return FFTWComplex(0,0);
492  double re = real.Interpolate(f,angle);
493  double im = imag.Interpolate(f,angle);
494 // printf("%f %f %f\n", f, re, im);
495 
496  return FFTWComplex(re,im);
497 }
498 
499 double AnitaResponse::AbstractResponse::getMagnitude(double f, double angle) const
500 {
501  return getResponse(f,angle).getAbs();
502 }
503 
504 double AnitaResponse::AbstractResponse::getPhase(double f, double angle) const
505 {
506  return getResponse(f,angle).getPhase();
507 }
508 
509 
510 
511 
512 
513 
514 AnalysisWaveform* AnitaResponse::AbstractResponse::impulseResponse(double dt, int N ) const
515 {
516  AnalysisWaveform * out = new AnalysisWaveform(N, dt);
517  out->updateEven()->GetY()[1] = 1;
518  convolveInPlace(out,0);
519  return out;
520 }
521 
522 void AnitaResponse::AbstractResponse::convolveInPlace(AnalysisWaveform * wf, double angle) const
523 {
524  int old_size = wf->Neven();
525 // wf->padEven(2);
526  int nf = wf->Nfreq();
527  double df = wf->deltaF();
528  FFTWComplex * fft = wf->updateFreq();
529  for (int i = 0; i < nf; i++)
530  {
531  fft[i] *= getResponse(i*df, angle);
532  }
533  wf->updateEven()->Set(old_size);
534 }
535 
536 AnalysisWaveform * AnitaResponse::AbstractResponse::convolve(const AnalysisWaveform * in, double off_axis_angle ) const
537 {
538 
539  //copy
540  AnalysisWaveform * out = new AnalysisWaveform(*in);
541  convolveInPlace(out, off_axis_angle);
542  return out;
543 }
544 
545 AnalysisWaveform * AnitaResponse::AbstractResponse::deconvolve(const AnalysisWaveform * in, const DeconvolutionMethod * method, double off_axis_angle) const
546 {
547 
548  //copy
549  AnalysisWaveform * out = new AnalysisWaveform(*in);
550  deconvolveInPlace(out,method,off_axis_angle);
551  return out;
552 }
553 
554 
556 static __thread const AnitaResponse::AbstractResponse *cache_response = 0;
557 static __thread int cache_Nt= 0;
558 static __thread double cache_df= 0;
559 static __thread double cache_angle= 0;
560 static __thread FFTWComplex *cache_V = 0;
561 static __thread AnalysisWaveform * cache_response_wf = 0;
562 
563 
564 void AnitaResponse::AbstractResponse::deconvolveInPlace(AnalysisWaveform * wf, const DeconvolutionMethod * method, double off_axis_angle) const
565 {
566 // printf("method: %p\n", method);
567  wf->padEven(1,0);
568  int nt = wf->Neven();
569  double df = wf->deltaF();
570  if (!cache_response || cache_Nt != nt || cache_df != df || !cache_V || cache_angle != off_axis_angle)
571  {
572  cache_response = this;
573  cache_Nt = nt;
574  cache_df = df;
575  cache_angle = off_axis_angle;
576  if (cache_V) delete [] cache_V;
577  int nf = nt/2+1;
578  cache_V = getResponseArray(nf,df,off_axis_angle);
579  if (cache_response_wf) delete cache_response_wf;
580  cache_response_wf = new AnalysisWaveform(nt, cache_V, df,0);
581  }
582 
583  method->deconvolve(wf, cache_response_wf);
584 // wf->updateEven()->Set(old_size);
585 
586 }
587 
588 
589 
591 //
592 
593 void AnitaResponse::CLEANDeconvolution::clearIntermediate() const
594 {
595 
596  for (unsigned i = 0; i < save_xcorr.size(); i++) delete save_xcorr[i];
597  for (unsigned i = 0; i < save_ys.size(); i++) delete save_ys[i];
598  for (unsigned i = 0; i < save_subtracted.size(); i++) delete save_subtracted[i];
599  save_xcorr.clear();
600  save_ys.clear();
601  save_subtracted.clear();
602 }
603 
604 void AnitaResponse::CLEANDeconvolution::deconvolve(AnalysisWaveform *y, const AnalysisWaveform * h) const
605 {
606 
607 
608  int Nt = y->Neven();
609  double dt = y->deltaT();
610  double t0 = y->even()->GetX()[0];
611  double T = dt *Nt;
612  int Nf =h->Nfreq();
613  double df = 1./dt/Nt;
614 
615  //now let's evaluate the restoring beam
616  //TODO: cache the last one since usually we'll be doing the same one over and over again
617 
618  if (!cached_restoring || Nt != cached_restoring->Neven() || dt != cached_restoring->deltaT())
619  {
620  if (cached_restoring) delete cached_restoring;
621  cached_restoring = new AnalysisWaveform(Nt,dt,-T/2);
622  TGraphAligned * grestore = cached_restoring->updateEven();
623  for (int i = 0; i < Nt; i++)
624  {
625  grestore->GetY()[i] = r->Eval(i*dt);
626  }
627  }
628 
629 
630  bool done = false;
631 
632  double hrms = h->getRMS();
633  double yrms = y->getRMS();
634  double power_ratio = yrms/hrms;
635 
636  cmp = AnalysisWaveform(Nt,dt,t0);
637 
638  int iter = 0;
639 
640  clearIntermediate();
641  double sqrt_threshold = sqrt(threshold);
642 
643  while(!done)
644  {
645  AnalysisWaveform * xcorr = AnalysisWaveform::correlation(y,h,0,hrms*yrms);
646 
647  int where;
648 
649  double maxcorr = xcorr->even()->peakVal(&where,0,-1,true);
650  if (xcorr->even()->GetY()[where] < 0) maxcorr *=-1;
651 
652  double lag = xcorr->even()->GetX()[where]-t0;
653 
654 
655 
656  //record the component here
657  cmp.updateEven()->GetY()[(int) (lag/dt)]+= maxcorr * gain;
658 
659 
660  if (debug)
661  {
662  save_ys.push_back(new AnalysisWaveform(*y));
663  save_ys.back()->setTitle(Form("iter%d pk2kpk = %g", iter, save_ys.back()->even()->pk2pk()));
664  }
665 
666 
667  //now subtract off impulse response with this offset
668  //We are currently in the frequency domain so let's stay there!
669  const std::complex<double> * H = (const std::complex<double>*) h->freq();
670  std::complex<double> * Y = (std::complex<double>*) y->updateFreq();
671 // printf ("\nSTART %d\n",iter);
672 //
673  AnalysisWaveform * subtracted = debug ? new AnalysisWaveform(*h) : 0;
674  if (debug) save_subtracted.push_back(subtracted);
675  FFTWComplex * subtracted_freq = debug ? subtracted->updateFreq() : 0;
676 
677  const double factor= (maxcorr*gain*power_ratio);
678  const double expo = -2./Nt*TMath::Pi()*lag/dt;
679  for (int i = 0; i < Nf; i++)
680  {
681  //this can be sped up using multiple angle formulas!
682  std::complex<double> subtract = factor * (H[i] * std::exp(std::complex<double>(0,i*expo)));
683  // printf("%g: %g %g ->", i *df, std::real(Y[i]), std::imag(Y[i]));
684  Y[i] -= subtract;
685  if (debug) subtracted_freq[i] = subtract;
686  // printf("%g %g\n", std::real(Y[i]), std::imag(Y[i]));
687  }
688 
689 
690  if (debug)
691  {
692  xcorr->setTitle(Form("lag=%g, max=%g",lag,maxcorr));
693  save_xcorr.push_back(xcorr) ;
694  }
695  else
696  {
697  delete xcorr;
698  }
699 
700  if (y->getRMS() / yrms < sqrt_threshold || iter++ > max_iter) break;
701  }
702 
703 
704  //now get rid of clean components below threshold
705 
706  double cc_max = fabs(cmp.even()->peakVal(0,0,-1,true));
707  cmp.updateEven()->setBelow(cc_max/noiselevel);
708 
709 
710  if (convolve_residuals)
711  {
712  //add clean components to y before convolving
713 
714 
715  FFTWComplex * yf = y->updateFreq();
716  const FFTWComplex *cf = cmp.freq();
717  for (int i = 0; i < Nf; i++)
718  {
719 
720  yf[i] += cf[i];
721  }
722 
723 
724  AnalysisWaveform * convolved = AnalysisWaveform::convolution(y,cached_restoring, 0, cached_restoring->getRMS() *y->getRMS());
725  *y = *convolved;
726  delete convolved;
727 
728  }
729  else
730  {
731  AnalysisWaveform * convolved = AnalysisWaveform::convolution(&cmp,cached_restoring, 0, cached_restoring->getRMS() *cmp.getRMS());
732 
733  //now add to residuals
734  //
735  TGraph * g = y->updateEven();
736  for (int i = 0; i < Nt; i++)
737  {
738  g->GetY()[i] += convolved->evalEven(g->GetX()[i]);
739  }
740 
741 
742  delete convolved;
743  }
744 
745 }
746 
747 
748 
double evalEven(double t, EvenEvaluationType=EVAL_LINEAR) const
WienerDeconvolution(const TGraph *g_snr, const double *scale=0)
TGraphAligned * updateEven()
const FFTWComplex * freq() const
This is a wrapper class for a complex number.
Definition: FFTWComplex.h:12
void padEven(int factor, int where=1)
double deltaT() const
Inelasticity distributions: stores parametrizations and picks inelasticities.
Definition: Primaries.h:38
double deltaF() const
static AnalysisWaveform * correlation(const AnalysisWaveform *A, const AnalysisWaveform *B, int npadfreq=0, double scale=1, int window_normalize=0)
const TGraphAligned * even() const
FFTWComplex * updateFreq()
This class is intended to be the main storage vessel for ANITA waveforms. It is similar in principle ...