SignalShaping.cxx
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////
2 ///
3 /// \file SignalShaping.cxx
4 ///
5 /// \brief Generic signal shaping class.
6 ///
7 /// \author H. Greenlee
8 ///
9 ////////////////////////////////////////////////////////////////////////
10 
11 #include <cmath>
12 #include "cetlib_except/exception.h"
14 
15 
16 //----------------------------------------------------------------------
17 // Constructor.
18 //
20  : fResponseLocked(false)
21  , fFilterLocked (false)
22  , fNorm (true)
23 {}
24 
25 
26 //----------------------------------------------------------------------
27 // Destructor.
28 //
30 {}
31 
32 // void util::SignalShaping::ResetDecon()
33 // {
34 // fResponseLocked = false;
35 // fFilterLocked = false;
36 // fResponse.clear();
37 // fConvKernel.clear();
38 // fFilter.clear();
39 // fDeconvKernel.clear();
40 // //Set deconvolution polarity to + as default
41 // fDeconvKernelPolarity = +1;
42 // }
43 
44 
45 //----------------------------------------------------------------------
46 // Reset this class to its default-constructed state.
48 {
49  fResponseLocked = false;
50  fFilterLocked = false;
51  fResponse.clear();
52  fConvKernel.clear();
53  fFilter.clear();
54  fDeconvKernel.clear();
55  //Set deconvolution polarity to + as default
57 }
58 
59 
60 //----------------------------------------------------------------------
61 // Add a time domain response function.
62 void util::SignalShaping::AddResponseFunction(const std::vector<double>& resp, bool ResetResponse )
63 {
64  // Make sure configuration is not locked.
65 
66  if(fResponseLocked)
67  throw cet::exception("SignalShaping") << "Configuration locked.\n";
68 
69  // Get FFT service.
70 
72  int nticks = fft->FFTSize();
73 
74  // Copy new response function into fResponse attribute, and pad or
75  // truncate to correct size.
76 
77  fResponse = resp;
78  fResponse.resize(nticks, 0.);
79 
80  // Is this the first response function?
81 
82  if ( fConvKernel.size() == 0 || ResetResponse ) {
83 
84  // This is the first response function.
85  // Just calculate the fourier transform.
86 
87  fConvKernel.resize(nticks/2 + 1);
89  }
90  else {
91 
92  // Not the first response function.
93  // Calculate the fourier transform of new response function.
94 
95  std::vector<TComplex> kern(nticks/2 + 1);
96  fft->DoFFT(fResponse, kern);
97 
98  // Update overall convolution kernel.
99 
100  if (kern.size() != fConvKernel.size()) {
101  throw cet::exception("SignalShaping") << __func__ << ": inconsistent kernel size, "
102  << kern.size() << " vs. " << fConvKernel.size();
103  }
104  for(unsigned int i=0; i<kern.size(); ++i)
105  fConvKernel[i] *= kern[i];
106 
107  // Recalculate overall response function.
108 
110  }
111 }
112 
113 
114 //----------------------------------------------------------------------
115 // Shift the response function and convolution kernel by the specified
116 // number of ticks.
118 {
119  // Make sure configuration is not locked.
120 
121  if(fResponseLocked)
122  throw cet::exception("SignalShaping") << "Configuration locked.\n";
123 
124  // Get FFT service.
125 
127 
128  // Update convolution kernel.
129 
130  fft->ShiftData(fConvKernel, ticks);
131 
132  // Recalculate overall response functiion.
133 
135 }
136 
137 
138 //----------------------------------------------------------------------
139 // Set the peak response time to be at the specified tick.
141 {
142  // Make sure configuration is not locked.
143 
144  if(fResponseLocked)
145  throw cet::exception("SignalShaping") << "Configuration locked.\n";
146 
147  // Get FFT service.
148 
150 
151  // Construct a delta-function response centered at tick zero.
152 
153  std::vector<double> delta(fft->FFTSize(), 0.);
154  delta[0] = 1.;
155 
156  // Figure out peak of current overall response.
157 
158  double peak = fft->PeakCorrelation(delta, fResponse);
159 
160  // Shift peak response to desired tick.
161 
162  ShiftResponseTime(tick - peak);
163 }
164 
165 
166 //----------------------------------------------------------------------
167 // Add a frequency domain filter function to cumulative filter function.
168 void util::SignalShaping::AddFilterFunction(const std::vector<TComplex>& filt)
169 {
170  // Make sure configuration is not locked.
171 
172  if(fFilterLocked)
173  throw cet::exception("SignalShaping") << "Configuration locked.\n";
174 
175  // Get FFT service.
176 
178 
179  // If this is the first filter function, just copy the filter function.
180  // Otherwise, update the overall filter function.
181 
182  if(fFilter.size() == 0) {
183  fFilter = filt;
184  fFilter.resize(fft->FFTSize() / 2 + 1);
185  }
186  else {
187  unsigned int n = std::min(fFilter.size(), filt.size());
188  for(unsigned int i=0; i<n; ++i)
189  fFilter[i] *= filt[i];
190  for(unsigned int i=n; i<fFilter.size(); ++i)
191  fFilter[i] = 0.;
192  }
193 }
194 
195 //----------------------------------------------------------------------
196 // Add a DeconvKernel Polarity Flag to decide how to normalize
198 {
199 
200  if ( (pol != 1) and (pol != -1) ) {
201  throw cet::exception("SignalShaping") << __func__
202  << ": DeconvKernelPolarity should be +1 or -1 (got " << pol << "). Setting to +1\n";
204  }
205 
206  else
207  fDeconvKernelPolarity = pol;
208 
209 }
210 
211 
212 //----------------------------------------------------------------------
213 // Test and lock the response and convolution kernel.
215 {
216  // Do nothing if the response is already locked.
217 
218  if(!fResponseLocked) {
219 
220  // Get FFT service.
221 
223 
224  // Make sure response has been configured.
225 
226  if(fResponse.size() == 0)
227  throw cet::exception("SignalShaping")
228  << "Response has not been configured.\n";
229 
230  // Make sure response and convolution kernel have the correct
231  // size (should always be the case if we get here).
232 
233  unsigned int n = fft->FFTSize();
234  if (fResponse.size() != n)
235  throw cet::exception("SignalShaping") << __func__ << ": inconsistent kernel size, "
236  << fResponse.size() << " vs. " << n << "\n";
237  if (2 * (fConvKernel.size() - 1) != n)
238  throw cet::exception("SignalShaping") << __func__ << ": unexpected FFT size, "
239  << n << " vs. expected " << (2 * (fConvKernel.size() - 1)) << "\n";
240 
241  // Set the lock flag.
242 
243  fResponseLocked = true;
244  }
245 }
246 
247 
248 //----------------------------------------------------------------------
249 // Calculate the deconvolution kernel as the ratio
250 // of the filter function and convolution kernel.
252 {
253  // Make sure configuration is not locked.
254 
255  if(fFilterLocked)
256  throw cet::exception("SignalShaping") << "Configuration locked.\n";
257 
258  // Lock response configuration.
259 
260  LockResponse();
261 
262  // Get FFT service.
263 
265 
266  // Make sure filter function has been configured.
267 
268  if(fFilter.size() == 0)
269  throw cet::exception("SignalShaping")
270  << "Filter function has not been configured.\n";
271 
272  // Make sure filter function has the correct size.
273  // (Should always be the case if we get here.)
274 
275  unsigned int n = fft->FFTSize();
276  if (2 * (fFilter.size() - 1) != n)
277  if (fFilter.size() != fConvKernel.size()) {
278  throw cet::exception("SignalShaping") << __func__ << ": inconsistent size, "
279  << fFilter.size() << " vs. " << fConvKernel.size() << "\n";
280  }
281 
282  // Calculate deconvolution kernel as the ratio of the
283  // filter function and the convolution kernel.
284 
286  for(unsigned int i=0; i<fDeconvKernel.size(); ++i) {
287  if(std::abs(fConvKernel[i].Re()) <= 0.0001 && std::abs(fConvKernel[i].Im()) <= 0.0001) {
288  fDeconvKernel[i] = 0.;
289  }
290  else {
291  fDeconvKernel[i] /= fConvKernel[i];
292  }
293  }
294 
295  // Normalize the deconvolution kernel.
296 
297  // Calculate the unnormalized deconvoluted response
298  // (inverse FFT of filter function).
299 
300  std::vector<double> deconv(n, 0.);
301  fft->DoInvFFT(const_cast<std::vector<TComplex>&>(fFilter), deconv);
302 
303  if (fNorm){
304  // Find the peak value of the response
305  // Should normally be at zero, but don't assume that.
306  // Use DeconvKernelPolairty to find what to normalize to
307  double peak_response = 0;
308  if ( fDeconvKernelPolarity == -1 )
309  peak_response = 4096;
310  for(unsigned int i = 0; i < fResponse.size(); ++i) {
311  if( (fResponse[i] > peak_response)
312  and (fDeconvKernelPolarity == 1))
313  peak_response = fResponse[i];
314  else if ( (fResponse[i] < peak_response)
315  and ( fDeconvKernelPolarity == -1) )
316  peak_response = fResponse[i];
317  }
318  if ( fDeconvKernelPolarity == -1 )
319  peak_response *= -1;
320  if (peak_response <= 0.) {
321  throw cet::exception("SignalShaping") << __func__
322  << ": peak should always be positive (got " << peak_response << ")\n";
323  }
324 
325  // Find the peak value of the deconvoluted response
326  // Should normally be at zero, but don't assume that.
327 
328  double peak_deconv = 0.;
329  for(unsigned int i = 0; i < deconv.size(); ++i) {
330  if(deconv[i] > peak_deconv)
331  peak_deconv = deconv[i];
332  }
333  if (peak_deconv <= 0.) {
334  throw cet::exception("SignalShaping") << __func__
335  << ": deconvolution peak should always be positive (got " << peak_deconv << ")\n";
336  }
337 
338  // Multiply the deconvolution kernel by a factor such that
339  // (Peak of response) = (Peak of deconvoluted response).
340 
341  double ratio = peak_response / peak_deconv;
342  for(unsigned int i = 0; i < fDeconvKernel.size(); ++i)
343  fDeconvKernel[i] *= ratio;
344  }
345  // Set the lock flag.
346 
347  fFilterLocked = true;
348 }
void ShiftData(std::vector< TComplex > &input, double shift)
std::vector< TComplex > fConvKernel
void AddResponseFunction(const std::vector< double > &resp, bool ResetResponse=false)
void LockResponse() const
std::vector< TComplex > fFilter
void DoFFT(std::vector< T > &input, std::vector< TComplex > &output)
Definition: LArFFT.h:98
T PeakCorrelation(std::vector< T > &shape1, std::vector< T > &shape2)
Definition: LArFFT.h:272
tick ticks
Alias for common language habits.
Definition: electronics.h:78
void DoInvFFT(std::vector< TComplex > &input, std::vector< T > &output)
Definition: LArFFT.h:120
T abs(T value)
Generic class for shaping signals on wires.
int FFTSize() const
Definition: LArFFT.h:69
void CalculateDeconvKernel() const
std::void_t< T > n
void SetDeconvKernelPolarity(int pol)
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
void ShiftResponseTime(double ticks)
std::vector< TComplex > fDeconvKernel
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
void SetPeakResponseTime(double tick)
std::vector< double > fResponse
void AddFilterFunction(const std::vector< TComplex > &filt)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33