All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
RawDigitFFTAlg.cxx
Go to the documentation of this file.
1 #include "RawDigitFFTAlg.h"
2 
3 #include "art/Framework/Services/Registry/ServiceHandle.h"
4 #include "art_root_io/TFileService.h"
5 #include "art/Framework/Core/ModuleMacros.h"
6 #include "art/Utilities/make_tool.h"
7 #include "messagefacility/MessageLogger/MessageLogger.h"
8 
12 
13 #include "icarus_signal_processing/WaveformTools.h"
15 
16 #include <cmath>
17 #include <algorithm>
18 
19 namespace caldata
20 {
21 
22 //----------------------------------------------------------------------------
23 /// Constructor.
24 ///
25 /// Arguments:
26 ///
27 /// pset - Fcl parameters.
28 ///
29 template <class T> RawDigitFFTAlg<T>::RawDigitFFTAlg(fhicl::ParameterSet const & pset)
30 {
31  reconfigure(pset);
32 
33  // Report.
34  mf::LogInfo("RawDigitFFTAlg") << "RawDigitFFTAlg configured\n";
35 }
36 
37 //----------------------------------------------------------------------------
38 /// Destructor.
40 {}
41 
42 //----------------------------------------------------------------------------
43 /// Reconfigure method.
44 ///
45 /// Arguments:
46 ///
47 /// pset - Fcl parameter set.
48 ///
49 template <class T> void RawDigitFFTAlg<T>::reconfigure(fhicl::ParameterSet const & pset)
50 {
51  fTransformViewVec = pset.get<std::vector<bool> >("TransformViewVec", std::vector<bool>() = {true,false,false});
52  fFillHistograms = pset.get<bool >("FillHistograms", false);
53  fHistDirName = pset.get<std::string >("HistDirName", "FFT_hists");
54  fLoWireByPlane = pset.get<std::vector<size_t>>("LoWireByPlane", std::vector<size_t>()={0,0,0});
55  fHiWireByPlane = pset.get<std::vector<size_t>>("HiWireByPlane", std::vector<size_t>()={100,100,100});
56 
57  // Implement the tools for handling the responses
58  const fhicl::ParameterSet& filterTools = pset.get<fhicl::ParameterSet>("FilterTools");
59 
60  for(const std::string& filterTool : filterTools.get_pset_names())
61  {
62  const fhicl::ParameterSet& filterToolParamSet = filterTools.get<fhicl::ParameterSet>(filterTool);
63  size_t planeIdx = filterToolParamSet.get<size_t>("Plane");
64 
65  fFilterToolMap.insert(std::pair<size_t,std::unique_ptr<icarus_tool::IFilter>>(planeIdx,art::make_tool<icarus_tool::IFilter>(filterToolParamSet)));
66  fFilterVecMap[planeIdx] = std::vector<std::complex<float>>();
67  }
68 
69  fEigenFFT = std::make_unique<Eigen::FFT<float>>();
70 }
71 
72 //----------------------------------------------------------------------------
73 /// Begin job method.
74 template <class T> void RawDigitFFTAlg<T>::initializeHists(detinfo::DetectorClocksData const& clockData,
76  art::ServiceHandle<art::TFileService>& tfs)
77 {
78  if (fFillHistograms)
79  {
80  // Define the histograms. Putting semi-colons around the title
81  // causes it to be displayed as the x-axis label if the histogram
82  // is drawn.
83 
84  // hijack hists here
85  double sampleRate = sampling_rate(clockData);
86  double readOutSize = detProp.ReadOutWindowSize();
87  double maxFreq = 1.e6 / (2. * sampleRate);
88  double minFreq = 1.e6 / (2. * sampleRate * readOutSize);
89  int numSamples = readOutSize / 2;
90 
91  // Make a directory for these histograms
92  art::TFileDirectory dir = tfs->mkdir(fHistDirName.c_str());
93 
94  fFFTPowerVec.resize(3);
95  fAveFFTPowerVec.resize(3);
96  fConvFFTPowerVec.resize(3);
97  fFilterFuncVec.resize(3);
98 
99  for(size_t plane = 0; plane < 3; plane++)
100  {
101  size_t numHists = fHiWireByPlane[plane] - fLoWireByPlane[plane];
102 
103  fFFTPowerVec[plane].resize(numHists);
104 
105  for(size_t idx = 0; idx < fHiWireByPlane[plane] - fLoWireByPlane[plane]; idx++)
106  {
107  std::string histName = "FFTPower_" + std::to_string(plane) + "-" + std::to_string(idx);
108 
109  fFFTPowerVec[plane][idx] = dir.make<TProfile>(histName.c_str(), "Power Spectrum;kHz;Power", numSamples, minFreq, maxFreq, 0., 10000.);
110  }
111 
112  std::string histName = "AveFFTPower_" + std::to_string(plane);
113 
114  fAveFFTPowerVec[plane] = dir.make<TProfile>(histName.c_str(), "Power Spectrum;kHz;Power", numSamples, minFreq, maxFreq, 0., 1000.);
115 
116  histName = "ConvFFTPower_" + std::to_string(plane);
117 
118  fConvFFTPowerVec[plane] = dir.make<TProfile>(histName.c_str(), "Power Spectrum;kHz;Power", numSamples, minFreq, maxFreq, 0., 1000.);
119 
120  histName = "FilterFunc_" + std::to_string(plane);
121 
122  fFilterFuncVec[plane] = dir.make<TProfile>(histName.c_str(), "Filter Function;kHz;Power", numSamples, minFreq, maxFreq, 0., 1000.);
123  }
124  }
125 
126  return;
127 }
128 
129 template <class T> void RawDigitFFTAlg<T>::getFFTCorrection(std::vector<T>& corValVec, double minPowerThreshold) const
130 {
131  // This version will take FFT of input waveform and then remove bins in the time domain with a power less
132  // than the threshold input above.
133  size_t const fftDataSize = corValVec.size();
134 
135  Eigen::FFT<T> eigenFFT;
136 
137  std::vector<std::complex<T>> fftOutputVec(corValVec.size());
138 
139  eigenFFT.fwd(fftOutputVec, corValVec);
140 
141  size_t halfFFTDataSize(fftDataSize/2 + 1);
142 
143  std::vector<T> powerVec(halfFFTDataSize);
144 
145  std::transform(fftOutputVec.begin(), fftOutputVec.begin() + halfFFTDataSize, powerVec.begin(), [](const auto& val){return std::abs(val);});
146 
147  // Want the first derivative
148  std::vector<T> firstDerivVec(powerVec.size());
149 
150  fWaveformTool.firstDerivative(powerVec, firstDerivVec);
151 
152  // Find the peaks
153  icarus_signal_processing::WaveformTools<float>::PeakTupleVec peakTupleVec;
154 
155  fWaveformTool.findPeaks(firstDerivVec.begin(),firstDerivVec.end(),peakTupleVec,minPowerThreshold,0);
156 
157  if (!peakTupleVec.empty())
158  {
159  for(const auto& peakTuple : peakTupleVec)
160  {
161  size_t startTick = std::get<0>(peakTuple);
162  size_t stopTick = std::get<2>(peakTuple);
163 
164  if (stopTick > startTick)
165  {
166  std::complex<T> slope = (fftOutputVec[stopTick] - fftOutputVec[startTick]) / T(stopTick - startTick);
167 
168  for(size_t tick = startTick; tick < stopTick; tick++)
169  {
170  std::complex<T> interpVal = fftOutputVec[startTick] + T(tick - startTick) * slope;
171 
172  fftOutputVec[tick] = interpVal;
173  //fftOutputVec[fftDataSize - tick - 1] = interpVal;
174  }
175  }
176  }
177 
178  std::vector<T> tmpVec(corValVec.size());
179 
180  eigenFFT.inv(tmpVec, fftOutputVec);
181 
182  std::transform(corValVec.begin(),corValVec.end(),tmpVec.begin(),corValVec.begin(),std::minus<T>());
183  }
184 
185  return;
186 }
187 
188 template<class T> void RawDigitFFTAlg<T>::getFFTCorrection(std::vector<T>& corValVec, size_t maxBin) const
189 {
190  // This version will take FFT of input waveform and then remove bins in the time domain above the
191  // cutoff frequency defined by maxBin passed in above
192  size_t const fftDataSize = corValVec.size();
193 
194  Eigen::FFT<T> eigenFFT;
195 
196  std::vector<std::complex<T>> fftOutputVec(corValVec.size());
197 
198  eigenFFT.fwd(fftOutputVec, corValVec);
199 
200  size_t halfFFTDataSize(fftDataSize/2);
201 
202  std::fill(fftOutputVec.begin() + maxBin, fftOutputVec.begin() + halfFFTDataSize, std::complex<T>(0.,0.));
203  std::fill(fftOutputVec.end() - maxBin - 1, fftOutputVec.end(), std::complex<T>(0.,0.));
204 
205  eigenFFT.inv(corValVec, fftOutputVec);
206 
207  return;
208 }
209 
210 template <class T> void RawDigitFFTAlg<T>::filterFFT(detinfo::DetectorClocksData const& clockData,
212  std::vector<short>& rawadc, size_t plane, size_t wire, float pedestal)
213 {
214  // Check there is something to do
215  if (!fTransformViewVec.at(plane)) return;
216 
217  // Step one is to setup and then get the FFT transform of the input waveform
218  size_t const fftDataSize = rawadc.size();
219  double sampleRate = sampling_rate(clockData);
220  double readOutSize = detProp.ReadOutWindowSize();
221 
222  if (fFFTInputVec.size() != fftDataSize) fFFTInputVec.resize(fftDataSize, 0.);
223 
224  std::transform(rawadc.begin(),rawadc.end(),fFFTInputVec.begin(),[pedestal](const auto& val){return float(float(val) - pedestal);});
225 
226  if (fFFTOutputVec.size() != fftDataSize) fFFTOutputVec.resize(fftDataSize);
227 
228  fEigenFFT->fwd(fFFTOutputVec,fFFTInputVec);
229 
230  size_t halfFFTDataSize(fftDataSize/2 + 1);
231 
232  if (fPowerVec.size() != halfFFTDataSize + 1) fPowerVec.resize(halfFFTDataSize + 1, 0.);
233 
234  std::transform(fFFTOutputVec.begin(), fFFTOutputVec.begin() + halfFFTDataSize, fPowerVec.begin(), [](const auto& complex){return std::abs(complex);});
235 
236  // Recover the filter function we are using...
237  const icarusutil::FrequencyVec& filter = fFilterToolMap.at(plane)->getResponseVec();
238  const std::vector<std::complex<float>>& filterVec = fFilterVecMap.at(plane);;
239 
240  // Make sure the filter has been correctly initialized
241  if (filter.size() != halfFFTDataSize)
242  {
243  fFilterToolMap.at(plane)->setResponse(fftDataSize,1.,1.);
244 
245  // Set up the internal FFT vector
246  fFilterVecMap.at(plane).reserve(halfFFTDataSize);
247  for(auto& complex : filter) fFilterVecMap.at(plane).emplace_back(complex);
248  }
249 
250  //std::transform(fFFTOutputVec.begin(), fFFTOutputVec.begin() + fFFTOutputVec.size()/2, filterVec.begin(), fFFTOutputVec.begin(), std::multiplies<std::complex<float>>());
251 
252  //for(size_t idx = 0; idx < fFFTOutputVec.size()/2; idx++) fFFTOutputVec[fFFTOutputVec.size() - idx - 1] = fFFTOutputVec[idx];
253 
254  std::transform(fFFTOutputVec.begin(), fFFTOutputVec.begin() + halfFFTDataSize, filterVec.begin(), fFFTOutputVec.begin(), std::multiplies<std::complex<float>>());
255 
256  for(size_t idx = 1; idx < fFFTOutputVec.size()/2; idx++) fFFTOutputVec[fFFTOutputVec.size() - idx] = fFFTOutputVec[idx];
257 
258  fEigenFFT->inv(fFFTInputVec, fFFTOutputVec);
259 
260  // Fill hists
261  if (fFillHistograms)
262  {
263  // Fill any individual wire histograms we want to look at
264  if (wire >= fLoWireByPlane[plane] && wire < fHiWireByPlane[plane])
265  {
266  // Fill the power spectrum histogram
267  for(size_t idx = 0; idx < halfFFTDataSize; idx++)
268  {
269  float freq = 1.e6 * float(idx + 1)/ (sampleRate * readOutSize);
270  fFFTPowerVec[plane][wire-fLoWireByPlane[plane]]->Fill(freq, std::min(fPowerVec[idx],float(999.)), 1.);
271  }
272  }
273 
274  for(size_t idx = 0; idx < halfFFTDataSize; idx++)
275  {
276  float freq = 1.e6 * float(idx + 1)/ (sampleRate * readOutSize);
277  fAveFFTPowerVec[plane]->Fill(freq, std::min(fPowerVec[idx],float(999.)), 1.);
278  }
279 
280  // Get the filter power vec
281  std::transform(fFFTOutputVec.begin(), fFFTOutputVec.begin() + halfFFTDataSize, fPowerVec.begin(), [](const auto& val){return std::abs(val);});
282 
283  for(size_t idx = 0; idx < halfFFTDataSize; idx++)
284  {
285  float freq = 1.e6 * float(idx)/ (sampleRate * readOutSize);
286  fConvFFTPowerVec[plane]->Fill(freq, std::min(fPowerVec[idx],float(999.)), 1.);
287  fFilterFuncVec[plane]->Fill(freq, double(std::abs(filter[idx])), 1.);
288  }
289  }
290 
291  // Finally, we invert the resulting time domain values to recover the new waveform
292  std::transform(fFFTInputVec.begin(), fFFTInputVec.end(), rawadc.begin(), [pedestal](const float& adc){return std::round(adc + pedestal);});
293 
294  return;
295 }
296 }
Utilities related to art service access.
static constexpr Sample_t transform(Sample_t sample)
for pfile in ack l reconfigure(.*) override"` do echo "checking $
std::vector< ComplexVal > FrequencyVec
void filterFFT(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, std::vector< short > &, size_t, size_t, float pedestal=0.)
T abs(T value)
void getFFTCorrection(std::vector< T > &, double) const
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
void reconfigure(fhicl::ParameterSet const &pset)
This is the interface class for a tool to handle a filter for the overall response.
void initializeHists(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, art::ServiceHandle< art::TFileService > &)
Begin job method.
tuple dir
Definition: dropbox.py:28
physics filters filter
~RawDigitFFTAlg()
Destructor.
Contains all timing reference information for the detector.
std::string to_string(WindowPattern const &pattern)
RawDigitFFTAlg(fhicl::ParameterSet const &pset)
art::ServiceHandle< art::TFileService > tfs
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
process_name can override from command line with o or output caldata
Definition: pid.fcl:40
art framework interface to geometry description
auto const detProp