All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SignalShaper.cxx
Go to the documentation of this file.
1 #include <cmath>
2 #include "cetlib_except/exception.h"
4 
5 
6 //----------------------------------------------------------------------
7 // Constructor.
8 //
9 util::SignalShaper::SignalShaper(int fftsize, std::string fftopt)
10  : fResponseLocked(false)
11  , fFilterLocked (false)
12  , fNorm (true)
13  , fFFTSize (fftsize)
14  , fFFTPlan(new util::LArFFTWPlan(fftsize,fftopt))
15  , fFFT(new util::LArFFTW(fftsize,fFFTPlan->fPlan,fFFTPlan->rPlan,0))
16 {}
17 
18 
19 //----------------------------------------------------------------------
20 // Destructor.
21 //
23 {}
24 
25 
26 //----------------------------------------------------------------------
27 // Reset this class to its default-constructed state.
29 {
30  fResponseLocked = false;
31  fFilterLocked = false;
32  fResponse.clear();
33  fConvKernel.clear();
34  fFilter.clear();
35  fDeconvKernel.clear();
36  //Set deconvolution polarity to + as default
37  fDeconvKernelPolarity = +1;
38 }
39 
40 
41 //----------------------------------------------------------------------
42 // Add a time domain response function.
43 void util::SignalShaper::AddResponseFunction(const std::vector<double>& resp, bool ResetResponse )
44 {
45  // Make sure configuration is not locked.
46 
47  if(fResponseLocked)
48  throw cet::exception("SignalShaper") << "Configuration locked.\n";
49 
50  int nticks = fFFTSize;
51 
52  // Copy new response function into fResponse attribute, and pad or
53  // truncate to correct size.
54 
55  fResponse = resp;
56  fResponse.resize(nticks, 0.);
57 
58  // Is this the first response function?
59 
60  if ( fConvKernel.size() == 0 || ResetResponse ) {
61 
62  // This is the first response function.
63  // Just calculate the fourier transform.
64 
65  fConvKernel.resize(nticks/2 + 1);
66  fFFT->DoFFT(fResponse, fConvKernel);
67  }
68  else {
69 
70  // Not the first response function.
71  // Calculate the fourier transform of new response function.
72 
73  std::vector<std::complex<double>> kern(nticks/2 + 1);
74  fFFT->DoFFT(fResponse, kern);
75 
76  // Update overall convolution kernel.
77 
78  if (kern.size() != fConvKernel.size()) {
79  throw cet::exception("SignalShaper") << __func__ << ": inconsistent kernel size, "
80  << kern.size() << " vs. " << fConvKernel.size();
81  }
82  for(unsigned int i=0; i<kern.size(); ++i)
83  fConvKernel[i] *= kern[i];
84 
85  // Recalculate overall response function.
86 
87  fFFT->DoInvFFT(fConvKernel, fResponse);
88  }
89 }
90 
91 
92 //----------------------------------------------------------------------
93 // Shift the response function and convolution kernel by the specified
94 // number of ticks.
96 {
97  // Make sure configuration is not locked.
98 
99  if(fResponseLocked)
100  throw cet::exception("SignalShaper") << "Configuration locked.\n";
101 
102  // Update convolution kernel.
103 
104  fFFT->ShiftData(fConvKernel, ticks);
105 
106  // Recalculate overall response functiion.
107 
108  fFFT->DoInvFFT(fConvKernel, fResponse);
109 }
110 
111 
112 //----------------------------------------------------------------------
113 // Set the peak response time to be at the specified tick.
115 {
116  // Make sure configuration is not locked.
117 
118  if(fResponseLocked)
119  throw cet::exception("SignalShaper") << "Configuration locked.\n";
120 
121  // Construct a delta-function response centered at tick zero.
122 
123  std::vector<double> delta(fFFTSize, 0.);
124  delta[0] = 1.;
125 
126  // Figure out peak of current overall response.
127 
128  double peak = fFFT->PeakCorrelation(delta, fResponse);
129 
130  // Shift peak response to desired tick.
131 
132  ShiftResponseTime(tick - peak);
133 }
134 
135 
136 //----------------------------------------------------------------------
137 // Add a frequency domain filter function to cumulative filter function.
138 void util::SignalShaper::AddFilterFunction(const std::vector<std::complex<double>>& filt)
139 {
140  // Make sure configuration is not locked.
141 
142  if(fFilterLocked)
143  throw cet::exception("SignalShaper") << "Configuration locked.\n";
144 
145  // If this is the first filter function, just copy the filter function.
146  // Otherwise, update the overall filter function.
147 
148  if(fFilter.size() == 0) {
149  fFilter = filt;
150  fFilter.resize(fFFTSize / 2 + 1);
151  }
152  else {
153  unsigned int n = std::min(fFilter.size(), filt.size());
154  for(unsigned int i=0; i<n; ++i)
155  fFilter[i] *= filt[i];
156  for(unsigned int i=n; i<fFilter.size(); ++i)
157  fFilter[i] = 0.;
158  }
159 }
160 
161 //----------------------------------------------------------------------
162 // Add a DeconvKernel Polarity Flag to decide how to normalize
164 {
165 
166  if ( (pol != 1) and (pol != -1) ) {
167  throw cet::exception("SignalShaper") << __func__
168  << ": DeconvKernelPolarity should be +1 or -1 (got " << pol << "). Setting to +1\n";
169  fDeconvKernelPolarity = +1;
170  }
171 
172  else
173  fDeconvKernelPolarity = pol;
174 
175 }
176 
177 
178 //----------------------------------------------------------------------
179 // Test and lock the response and convolution kernel.
181 {
182  // Do nothing if the response is already locked.
183 
184  if(!fResponseLocked) {
185 
186  // Make sure response has been configured.
187 
188  if(fResponse.size() == 0)
189  throw cet::exception("SignalShaper")
190  << "Response has not been configured.\n";
191 
192  // Make sure response and convolution kernel have the correct
193  // size (should always be the case if we get here).
194 
195  unsigned int n = fFFTSize;
196  if (fResponse.size() != n)
197  throw cet::exception("SignalShaper") << __func__ << ": inconsistent kernel size, "
198  << fResponse.size() << " vs. " << n << "\n";
199  if (2 * (fConvKernel.size() - 1) != n)
200  throw cet::exception("SignalShaper") << __func__ << ": unexpected FFT size, "
201  << n << " vs. expected " << (2 * (fConvKernel.size() - 1)) << "\n";
202 
203  // Set the lock flag.
204 
205  fResponseLocked = true;
206  }
207 }
208 
209 
210 //----------------------------------------------------------------------
211 // Calculate the deconvolution kernel as the ratio
212 // of the filter function and convolution kernel.
214 {
215  // Make sure configuration is not locked.
216 
217  if(fFilterLocked)
218  throw cet::exception("SignalShaper") << "Configuration locked.\n";
219 
220  // Lock response configuration.
221 
222  LockResponse();
223 
224  // Make sure filter function has been configured.
225 
226  if(fFilter.size() == 0)
227  throw cet::exception("SignalShaper")
228  << "Filter function has not been configured.\n";
229 
230  // Make sure filter function has the correct size.
231  // (Should always be the case if we get here.)
232 
233  unsigned int n = fFFTSize;
234  if (2 * (fFilter.size() - 1) != n)
235  if (fFilter.size() != fConvKernel.size()) {
236  throw cet::exception("SignalShaper") << __func__ << ": inconsistent size, "
237  << fFilter.size() << " vs. " << fConvKernel.size() << "\n";
238  }
239 
240  // Calculate deconvolution kernel as the ratio of the
241  // filter function and the convolution kernel.
242 
243  fDeconvKernel = fFilter;
244  for(unsigned int i=0; i<fDeconvKernel.size(); ++i) {
245  if(std::abs(fConvKernel[i].real()) <= 0.0001 && std::abs(fConvKernel[i].imag()) <= 0.0001) {
246  fDeconvKernel[i] = 0.;
247  }
248  else {
249  fDeconvKernel[i] /= fConvKernel[i];
250  }
251  }
252 
253  // Normalize the deconvolution kernel.
254 
255  // Calculate the unnormalized deconvoluted response
256  // (inverse FFT of filter function).
257 
258  std::vector<double> deconv(n, 0.);
259  fFFT->DoInvFFT(const_cast<std::vector<std::complex<double>>&>(fFilter), deconv);
260  //fFFT->DoInvFFT(fFilter, deconv);
261 
262  if (fNorm){
263  // Find the peak value of the response
264  // Should normally be at zero, but don't assume that.
265  // Use DeconvKernelPolairty to find what to normalize to
266  double peak_response = 0;
267  if ( fDeconvKernelPolarity == -1 )
268  peak_response = 4096;
269  for(unsigned int i = 0; i < fResponse.size(); ++i) {
270  if( (fResponse[i] > peak_response)
271  and (fDeconvKernelPolarity == 1))
272  peak_response = fResponse[i];
273  else if ( (fResponse[i] < peak_response)
274  and ( fDeconvKernelPolarity == -1) )
275  peak_response = fResponse[i];
276  }
277  if ( fDeconvKernelPolarity == -1 )
278  peak_response *= -1;
279  if (peak_response <= 0.) {
280  throw cet::exception("SignalShaper") << __func__
281  << ": peak should always be positive (got " << peak_response << ")\n";
282  }
283 
284  // Find the peak value of the deconvoluted response
285  // Should normally be at zero, but don't assume that.
286 
287  double peak_deconv = 0.;
288  for(unsigned int i = 0; i < deconv.size(); ++i) {
289  if(deconv[i] > peak_deconv)
290  peak_deconv = deconv[i];
291  }
292  if (peak_deconv <= 0.) {
293  throw cet::exception("SignalShaper") << __func__
294  << ": deconvolution peak should always be positive (got " << peak_deconv << ")\n";
295  }
296 
297  // Multiply the deconvolution kernel by a factor such that
298  // (Peak of response) = (Peak of deconvoluted response).
299 
300  double ratio = peak_response / peak_deconv;
301  for(unsigned int i = 0; i < fDeconvKernel.size(); ++i)
302  fDeconvKernel[i] *= ratio;
303  }
304 
305  // Set the lock flag.
306 
307  fFilterLocked = true;
308 }
void CalculateDeconvKernel() const
void AddFilterFunction(const std::vector< std::complex< double >> &filt)
void ShiftResponseTime(double ticks)
virtual ~SignalShaper()
void SetPeakResponseTime(double tick)
tick ticks
Alias for common language habits.
Definition: electronics.h:78
void AddResponseFunction(const std::vector< double > &resp, bool ResetResponse=false)
void LockResponse() const
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
T abs(T value)
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
SignalShaper(int fftsize, std::string fftopt)
Definition: SignalShaper.cxx:9
then filt
void SetDeconvKernelPolarity(int pol)
BEGIN_PROLOG don t mess with this pandoraTrackGausCryoW true