1 /*****************************************************************************
5 ** Purpose: Routines for signal-procesing filters
6 ** Progammer: Kevin Rosenberg
7 ** Date Started: Aug 1984
9 ** This is part of the CTSim program
10 ** Copyright (C) 1983-2000 Kevin Rosenberg
12 ** $Id: procsignal.cpp,v 1.15 2001/01/12 03:49:07 kevin Exp $
14 ** This program is free software; you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License (version 2) as
16 ** published by the Free Software Foundation.
18 ** This program is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ** GNU General Public License for more details.
23 ** You should have received a copy of the GNU General Public License
24 ** along with this program; if not, write to the Free Software
25 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 ******************************************************************************/
30 // FilterMethod ID/Names
31 const int ProcessSignal::FILTER_METHOD_INVALID = -1;
32 const int ProcessSignal::FILTER_METHOD_CONVOLUTION = 0;
33 const int ProcessSignal::FILTER_METHOD_FOURIER = 1;
34 const int ProcessSignal::FILTER_METHOD_FOURIER_TABLE = 2;
35 const int ProcessSignal::FILTER_METHOD_FFT = 3;
37 const int ProcessSignal::FILTER_METHOD_FFTW = 4;
38 const int ProcessSignal::FILTER_METHOD_RFFTW =5 ;
40 const char* ProcessSignal::s_aszFilterMethodName[] = {
50 const char* ProcessSignal::s_aszFilterMethodTitle[] = {
53 {"Fouier Trigometric Table"},
57 {"Real/Half-Complex FFTW"},
60 const int ProcessSignal::s_iFilterMethodCount = sizeof(s_aszFilterMethodName) / sizeof(const char*);
62 // FilterGeneration ID/Names
63 const int ProcessSignal::FILTER_GENERATION_INVALID = -1;
64 const int ProcessSignal::FILTER_GENERATION_DIRECT = 0;
65 const int ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER = 1;
66 const char* ProcessSignal::s_aszFilterGenerationName[] = {
70 const char* ProcessSignal::s_aszFilterGenerationTitle[] = {
74 const int ProcessSignal::s_iFilterGenerationCount = sizeof(s_aszFilterGenerationName) / sizeof(const char*);
77 // CLASS IDENTIFICATION
80 ProcessSignal::ProcessSignal (const char* szFilterName, const char* szFilterMethodName, double dBandwidth,
81 double dSignalIncrement, int nSignalPoints, double dFilterParam, const char* szDomainName,
82 const char* szFilterGenerationName, int iZeropad, int iPreinterpolationFactor, int iTraceLevel,
83 int iGeometry, double dFocalLength, SGP* pSGP)
84 : m_adFourierCosTable(NULL), m_adFourierSinTable(NULL), m_adFilter(NULL), m_fail(false)
86 m_idFilterMethod = convertFilterMethodNameToID (szFilterMethodName);
87 if (m_idFilterMethod == FILTER_METHOD_INVALID) {
89 m_failMessage = "Invalid filter method name ";
90 m_failMessage += szFilterMethodName;
93 m_idFilterGeneration = convertFilterGenerationNameToID (szFilterGenerationName);
94 if (m_idFilterGeneration == FILTER_GENERATION_INVALID) {
96 m_failMessage = "Invalid frequency filter name ";
97 m_failMessage += szFilterGenerationName;
100 m_idFilter = SignalFilter::convertFilterNameToID (szFilterName);
101 if (m_idFilter == SignalFilter::FILTER_INVALID) {
103 m_failMessage = "Invalid Filter name ";
104 m_failMessage += szFilterName;
107 m_idDomain = SignalFilter::convertDomainNameToID (szDomainName);
108 if (m_idDomain == SignalFilter::DOMAIN_INVALID) {
110 m_failMessage = "Invalid domain name ";
111 m_failMessage += szDomainName;
115 init (m_idFilter, m_idFilterMethod, dBandwidth, dSignalIncrement, nSignalPoints, dFilterParam, m_idDomain,
116 m_idFilterGeneration, iZeropad, iPreinterpolationFactor, iTraceLevel, iGeometry, dFocalLength, pSGP);
121 ProcessSignal::init (const int idFilter, const int idFilterMethod, double dBandwidth, double dSignalIncrement,
122 int nSignalPoints, double dFilterParam, const int idDomain, const int idFilterGeneration,
123 const int iZeropad, const int iPreinterpolationFactor, int iTraceLevel, int iGeometry,
124 double dFocalLength, SGP* pSGP)
127 m_idFilter = idFilter;
128 m_idDomain = idDomain;
129 m_idFilterMethod = idFilterMethod;
130 m_idFilterGeneration = idFilterGeneration;
131 m_idGeometry = iGeometry;
132 m_dFocalLength = dFocalLength;
134 if (m_idFilter == SignalFilter::FILTER_INVALID || m_idDomain == SignalFilter::DOMAIN_INVALID || m_idFilterMethod == FILTER_METHOD_INVALID || m_idFilterGeneration == FILTER_GENERATION_INVALID) {
138 m_traceLevel = iTraceLevel;
139 m_nameFilterMethod = convertFilterMethodIDToName (m_idFilterMethod);
140 m_nameFilterGeneration = convertFilterGenerationIDToName (m_idFilterGeneration);
141 m_dBandwidth = dBandwidth;
142 m_nSignalPoints = nSignalPoints;
143 m_dSignalInc = dSignalIncrement;
144 m_dFilterParam = dFilterParam;
145 m_iZeropad = iZeropad;
146 m_iPreinterpolationFactor = iPreinterpolationFactor;
148 // scale signalInc/BW to signalInc/2 to adjust for imaginary detector
149 // through origin of phantom rather than 2 times distance to detector,
150 // see Kak-Slaney Fig 3.22, for Collinear diagram
151 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
156 if (m_idFilterMethod == FILTER_METHOD_FFT) {
158 m_idFilterMethod = FILTER_METHOD_RFFTW;
161 m_failMessage = "FFT not yet implemented";
166 bool m_bFrequencyFiltering = true;
167 if (m_idFilterMethod == FILTER_METHOD_CONVOLUTION)
168 m_bFrequencyFiltering = false;
170 // Spatial-based filtering
171 if (! m_bFrequencyFiltering) {
173 if (m_idFilterGeneration == FILTER_GENERATION_DIRECT) {
174 m_nFilterPoints = 2 * (m_nSignalPoints - 1) + 1;
175 m_dFilterMin = -m_dSignalInc * (m_nSignalPoints - 1);
176 m_dFilterMax = m_dSignalInc * (m_nSignalPoints - 1);
177 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
178 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, m_nFilterPoints, m_dBandwidth, m_dFilterParam, SignalFilter::DOMAIN_SPATIAL);
179 m_adFilter = new double[ m_nFilterPoints ];
180 filter.copyFilterData (m_adFilter, 0, m_nFilterPoints);
181 } else if (m_idFilterGeneration == FILTER_GENERATION_INVERSE_FOURIER) {
182 m_nFilterPoints = 2 * (m_nSignalPoints - 1) + 1;
183 m_dFilterMin = -1. / (2 * m_dSignalInc);
184 m_dFilterMax = 1. / (2 * m_dSignalInc);
185 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
186 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, m_nFilterPoints, m_dBandwidth, m_dFilterParam, SignalFilter::DOMAIN_FREQUENCY);
187 m_adFilter = new double[ m_nFilterPoints ];
188 double* adFrequencyFilter = new double [m_nFilterPoints];
189 filter.copyFilterData (adFrequencyFilter, 0, m_nFilterPoints);
191 EZPlot* pEZPlot = NULL;
192 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
193 pEZPlot = new EZPlot ();
194 pEZPlot->ezset ("title Filter Response: Natural Order");
195 pEZPlot->ezset ("ylength 0.25");
196 pEZPlot->addCurve (adFrequencyFilter, m_nFilterPoints);
197 pEZPlot->plot (pSGP);
200 Fourier::shuffleNaturalToFourierOrder (adFrequencyFilter, m_nFilterPoints);
202 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
203 pEZPlot->ezset ("title Filter Response: Fourier Order");
204 pEZPlot->ezset ("ylength 0.25");
205 pEZPlot->ezset ("yporigin 0.25");
206 pEZPlot->addCurve (adFrequencyFilter, m_nFilterPoints);
207 pEZPlot->plot (pSGP);
210 ProcessSignal::finiteFourierTransform (adFrequencyFilter, m_adFilter, m_nFilterPoints, FORWARD);
211 delete adFrequencyFilter;
213 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
214 pEZPlot->ezset ("title Inverse Fourier Frequency: Fourier Order");
215 pEZPlot->ezset ("ylength 0.25");
216 pEZPlot->ezset ("yporigin 0.50");
217 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
218 pEZPlot->plot (pSGP);
221 Fourier::shuffleFourierToNaturalOrder (m_adFilter, m_nFilterPoints);
223 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
224 pEZPlot->ezset ("title Inverse Fourier Frequency: Natural Order");
225 pEZPlot->ezset ("ylength 0.25");
226 pEZPlot->ezset ("yporigin 0.75");
227 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
228 pEZPlot->plot (pSGP);
232 for (i = 0; i < m_nFilterPoints; i++) {
233 m_adFilter[i] /= m_dSignalInc;
236 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
237 for (i = 0; i < m_nFilterPoints; i++)
238 m_adFilter[i] *= 0.5;
239 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
240 for (i = 0; i < m_nFilterPoints; i++) {
241 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
242 double sinScale = sin (iDetFromZero * m_dSignalInc);
243 if (fabs(sinScale) < 1E-7)
246 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
247 double dScale = 0.5 * sinScale * sinScale;
248 m_adFilter[i] *= dScale;
251 } // if (spatial filtering)
253 else if (m_bFrequencyFiltering) { // Frequency-based filtering
255 if (m_idFilterGeneration == FILTER_GENERATION_DIRECT) {
256 // calculate number of filter points with zeropadding
257 m_nFilterPoints = m_nSignalPoints;
258 if (m_iZeropad > 0) {
259 double logBase2 = log(m_nFilterPoints) / log(2);
260 int nextPowerOf2 = static_cast<int>(floor(logBase2));
261 if (logBase2 != floor(logBase2))
263 nextPowerOf2 += (m_iZeropad - 1);
264 m_nFilterPoints = 1 << nextPowerOf2;
266 if (m_traceLevel >= Trace::TRACE_CONSOLE)
267 std::cout << "nFilterPoints = " << m_nFilterPoints << endl;
270 m_nOutputPoints = m_nFilterPoints * m_iPreinterpolationFactor;
272 if (m_nFilterPoints % 2) { // Odd
273 m_dFilterMin = -1. / (2 * m_dSignalInc);
274 m_dFilterMax = 1. / (2 * m_dSignalInc);
275 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
277 m_dFilterMin = -1. / (2 * m_dSignalInc);
278 m_dFilterMax = 1. / (2 * m_dSignalInc);
279 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / m_nFilterPoints;
280 m_dFilterMax -= m_dFilterInc;
283 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, m_nFilterPoints, m_dBandwidth, m_dFilterParam, SignalFilter::DOMAIN_FREQUENCY);
284 m_adFilter = new double [m_nFilterPoints];
285 filter.copyFilterData (m_adFilter, 0, m_nFilterPoints);
287 // This doesn't work!
288 // Need to add filtering for divergent geometries & Frequency/Direct filtering
289 // Jan 2001: Direct seems to work for equilinear and equiangular
290 // however, inverse_fourier doesn't work for equiangular on all versions of CTSim tested
292 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
293 for (i = 0; i < m_nFilterPoints; i++)
294 m_adFilter[i] *= 0.5;
295 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
296 for (i = 0; i < m_nFilterPoints; i++) {
297 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
298 double sinScale = sin (iDetFromZero * m_dSignalInc);
299 if (fabs(sinScale) < 1E-7)
302 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
303 double dScale = 0.5 * sinScale * sinScale;
304 m_adFilter[i] *= dScale;
308 EZPlot* pEZPlot = NULL;
309 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
310 pEZPlot = new EZPlot;
311 pEZPlot->ezset ("title Filter Filter: Natural Order");
312 pEZPlot->ezset ("ylength 0.50");
313 pEZPlot->ezset ("yporigin 0.00");
314 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
315 pEZPlot->plot (pSGP);
318 Fourier::shuffleNaturalToFourierOrder (m_adFilter, m_nFilterPoints);
320 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
321 pEZPlot->ezset ("title Filter Filter: Fourier Order");
322 pEZPlot->ezset ("ylength 0.50");
323 pEZPlot->ezset ("yporigin 0.50");
324 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
325 pEZPlot->plot (pSGP);
329 } else if (m_idFilterGeneration == FILTER_GENERATION_INVERSE_FOURIER) {
330 // calculate number of filter points with zeropadding
331 int nSpatialPoints = 2 * (m_nSignalPoints - 1) + 1;
332 m_dFilterMin = -m_dSignalInc * (m_nSignalPoints - 1);
333 m_dFilterMax = m_dSignalInc * (m_nSignalPoints - 1);
334 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (nSpatialPoints - 1);
335 m_nFilterPoints = nSpatialPoints;
336 if (m_iZeropad > 0) {
337 double logBase2 = log(nSpatialPoints) / log(2);
338 int nextPowerOf2 = static_cast<int>(floor(logBase2));
339 if (logBase2 != floor(logBase2))
341 nextPowerOf2 += (m_iZeropad - 1);
342 m_nFilterPoints = 1 << nextPowerOf2;
344 m_nOutputPoints = m_nFilterPoints * m_iPreinterpolationFactor;
346 if (m_traceLevel >= Trace::TRACE_CONSOLE)
347 std::cout << "nFilterPoints = " << m_nFilterPoints << endl;
349 double* adSpatialFilter = new double [m_nFilterPoints];
350 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, nSpatialPoints, m_dBandwidth, m_dFilterParam, SignalFilter::DOMAIN_SPATIAL);
351 filter.copyFilterData (adSpatialFilter, 0, nSpatialPoints);
353 EZPlot* pEZPlot = NULL;
354 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
355 pEZPlot = new EZPlot;
356 pEZPlot->ezset ("title Spatial Filter: Natural Order");
357 pEZPlot->ezset ("ylength 0.50");
358 pEZPlot->ezset ("yporigin 0.00");
359 pEZPlot->addCurve (adSpatialFilter, nSpatialPoints);
360 pEZPlot->plot (pSGP);
365 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
366 for (i = 0; i < m_nFilterPoints; i++)
367 adSpatialFilter[i] *= 0.5;
368 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
369 for (i = 0; i < m_nFilterPoints; i++) {
370 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
371 double sinScale = sin (iDetFromZero * m_dSignalInc);
372 if (fabs(sinScale) < 1E-7)
375 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
376 double dScale = 0.5 * sinScale * sinScale;
377 adSpatialFilter[i] *= dScale;
380 for (i = nSpatialPoints; i < m_nFilterPoints; i++)
381 adSpatialFilter[i] = 0;
383 m_adFilter = new double [m_nFilterPoints];
384 std::complex<double>* acInverseFilter = new std::complex<double> [m_nFilterPoints];
385 finiteFourierTransform (adSpatialFilter, acInverseFilter, m_nFilterPoints, BACKWARD);
386 delete adSpatialFilter;
387 for (i = 0; i < m_nFilterPoints; i++)
388 m_adFilter[i] = std::abs (acInverseFilter[i]) * m_dSignalInc;
389 delete acInverseFilter;
392 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
393 pEZPlot->ezset ("title Spatial Filter: Inverse");
394 pEZPlot->ezset ("ylength 0.50");
395 pEZPlot->ezset ("yporigin 0.50");
396 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
397 pEZPlot->plot (pSGP);
404 // precalculate sin and cosine tables for fourier transform
405 if (m_idFilterMethod == FILTER_METHOD_FOURIER_TABLE) {
406 int nFourier = imax (m_nFilterPoints,m_nOutputPoints) * imax (m_nFilterPoints, m_nOutputPoints) + 1;
407 double angleIncrement = (2. * PI) / m_nFilterPoints;
408 m_adFourierCosTable = new double[ nFourier ];
409 m_adFourierSinTable = new double[ nFourier ];
411 for (i = 0; i < nFourier; i++) {
412 m_adFourierCosTable[i] = cos (angle);
413 m_adFourierSinTable[i] = sin (angle);
414 angle += angleIncrement;
419 if (m_idFilterMethod == FILTER_METHOD_FFTW || m_idFilterMethod == FILTER_METHOD_RFFTW) {
420 for (i = 0; i < m_nFilterPoints; i++) //fftw uses unnormalized fft
421 m_adFilter[i] /= m_nFilterPoints;
424 if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
425 m_realPlanForward = rfftw_create_plan (m_nFilterPoints, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
426 m_realPlanBackward = rfftw_create_plan (m_nOutputPoints, FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE);
427 m_adRealFftInput = new fftw_real [ m_nFilterPoints ];
428 m_adRealFftSignal = new fftw_real [ m_nOutputPoints ];
429 for (i = 0; i < m_nFilterPoints; i++)
430 m_adRealFftInput[i] = 0;
431 } else if (m_idFilterMethod == FILTER_METHOD_FFTW) {
432 m_complexPlanForward = fftw_create_plan (m_nFilterPoints, FFTW_FORWARD, FFTW_ESTIMATE);
433 m_complexPlanBackward = fftw_create_plan (m_nOutputPoints, FFTW_BACKWARD, FFTW_ESTIMATE);
434 m_adComplexFftInput = new fftw_complex [ m_nFilterPoints ];
435 m_adComplexFftSignal = new fftw_complex [ m_nOutputPoints ];
436 for (i = 0; i < m_nFilterPoints; i++)
437 m_adComplexFftInput[i].re = m_adComplexFftInput[i].im = 0;
438 for (i = 0; i < m_nOutputPoints; i++)
439 m_adComplexFftSignal[i].re = m_adComplexFftSignal[i].im = 0;
445 ProcessSignal::~ProcessSignal (void)
447 delete [] m_adFourierSinTable;
448 delete [] m_adFourierCosTable;
449 delete [] m_adFilter;
452 if (m_idFilterMethod == FILTER_METHOD_FFTW) {
453 fftw_destroy_plan(m_complexPlanForward);
454 fftw_destroy_plan(m_complexPlanBackward);
455 delete [] m_adComplexFftInput;
456 delete [] m_adComplexFftSignal;
458 if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
459 rfftw_destroy_plan(m_realPlanForward);
460 rfftw_destroy_plan(m_realPlanBackward);
461 delete [] m_adRealFftInput;
462 delete [] m_adRealFftSignal;
468 ProcessSignal::convertFilterMethodNameToID (const char* const filterMethodName)
470 int fmID = FILTER_METHOD_INVALID;
472 for (int i = 0; i < s_iFilterMethodCount; i++)
473 if (strcasecmp (filterMethodName, s_aszFilterMethodName[i]) == 0) {
482 ProcessSignal::convertFilterMethodIDToName (const int fmID)
484 static const char *name = "";
486 if (fmID >= 0 && fmID < s_iFilterMethodCount)
487 return (s_aszFilterMethodName [fmID]);
493 ProcessSignal::convertFilterMethodIDToTitle (const int fmID)
495 static const char *title = "";
497 if (fmID >= 0 && fmID < s_iFilterMethodCount)
498 return (s_aszFilterMethodTitle [fmID]);
505 ProcessSignal::convertFilterGenerationNameToID (const char* const fgName)
507 int fgID = FILTER_GENERATION_INVALID;
509 for (int i = 0; i < s_iFilterGenerationCount; i++)
510 if (strcasecmp (fgName, s_aszFilterGenerationName[i]) == 0) {
519 ProcessSignal::convertFilterGenerationIDToName (const int fgID)
521 static const char *name = "";
523 if (fgID >= 0 && fgID < s_iFilterGenerationCount)
524 return (s_aszFilterGenerationName [fgID]);
530 ProcessSignal::convertFilterGenerationIDToTitle (const int fgID)
532 static const char *name = "";
534 if (fgID >= 0 && fgID < s_iFilterGenerationCount)
535 return (s_aszFilterGenerationTitle [fgID]);
541 ProcessSignal::filterSignal (const float constInput[], double output[]) const
543 double* input = new double [m_nSignalPoints];
545 for (i = 0; i < m_nSignalPoints; i++)
546 input[i] = constInput[i];
548 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
549 for (int i = 0; i < m_nSignalPoints; i++) {
550 int iDetFromCenter = i - (m_nSignalPoints / 2);
551 input[i] *= m_dFocalLength / sqrt (m_dFocalLength * m_dFocalLength + iDetFromCenter * iDetFromCenter * m_dSignalInc * m_dSignalInc);
553 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
554 for (int i = 0; i < m_nSignalPoints; i++) {
555 int iDetFromCenter = i - (m_nSignalPoints / 2);
556 input[i] *= m_dFocalLength * cos (iDetFromCenter * m_dSignalInc);
559 if (m_idFilterMethod == FILTER_METHOD_CONVOLUTION) {
560 for (i = 0; i < m_nSignalPoints; i++)
561 output[i] = convolve (input, m_dSignalInc, i, m_nSignalPoints);
562 } else if (m_idFilterMethod == FILTER_METHOD_FOURIER) {
563 double* inputSignal = new double [m_nFilterPoints];
564 for (i = 0; i < m_nSignalPoints; i++)
565 inputSignal[i] = input[i];
566 for (i = m_nSignalPoints; i < m_nFilterPoints; i++)
567 inputSignal[i] = 0; // zeropad
568 std::complex<double>* fftSignal = new std::complex<double> [m_nFilterPoints];
569 finiteFourierTransform (inputSignal, fftSignal, m_nFilterPoints, FORWARD);
571 for (i = 0; i < m_nFilterPoints; i++)
572 fftSignal[i] *= m_adFilter[i];
573 double* inverseFourier = new double [m_nFilterPoints];
574 finiteFourierTransform (fftSignal, inverseFourier, m_nFilterPoints, BACKWARD);
576 for (i = 0; i < m_nSignalPoints; i++)
577 output[i] = inverseFourier[i];
578 delete inverseFourier;
579 } else if (m_idFilterMethod == FILTER_METHOD_FOURIER_TABLE) {
580 double* inputSignal = new double [m_nFilterPoints];
581 for (i = 0; i < m_nSignalPoints; i++)
582 inputSignal[i] = input[i];
583 for (i = m_nSignalPoints; i < m_nFilterPoints; i++)
584 inputSignal[i] = 0; // zeropad
585 std::complex<double>* fftSignal = new std::complex<double> [m_nFilterPoints];
586 finiteFourierTransform (inputSignal, fftSignal, FORWARD);
588 for (i = 0; i < m_nFilterPoints; i++)
589 fftSignal[i] *= m_adFilter[i];
590 double* inverseFourier = new double [m_nFilterPoints];
591 finiteFourierTransform (fftSignal, inverseFourier, BACKWARD);
593 for (i = 0; i < m_nSignalPoints; i++)
594 output[i] = inverseFourier[i];
595 delete inverseFourier;
598 else if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
599 for (i = 0; i < m_nSignalPoints; i++)
600 m_adRealFftInput[i] = input[i];
602 fftw_real* fftOutput = new fftw_real [ m_nFilterPoints ];
603 rfftw_one (m_realPlanForward, m_adRealFftInput, fftOutput);
604 for (i = 0; i < m_nFilterPoints; i++)
605 m_adRealFftSignal[i] = m_adFilter[i] * fftOutput[i];
607 for (i = m_nFilterPoints; i < m_nOutputPoints; i++)
608 m_adRealFftSignal[i] = 0;
610 fftw_real* ifftOutput = new fftw_real [ m_nOutputPoints ];
611 rfftw_one (m_realPlanBackward, m_adRealFftSignal, ifftOutput);
612 for (i = 0; i < m_nSignalPoints * m_iPreinterpolationFactor; i++)
613 output[i] = ifftOutput[i];
614 delete [] ifftOutput;
615 } else if (m_idFilterMethod == FILTER_METHOD_FFTW) {
616 for (i = 0; i < m_nSignalPoints; i++)
617 m_adComplexFftInput[i].re = input[i];
619 fftw_complex* fftOutput = new fftw_complex [ m_nFilterPoints ];
620 fftw_one (m_complexPlanForward, m_adComplexFftInput, fftOutput);
621 for (i = 0; i < m_nFilterPoints; i++) {
622 m_adComplexFftSignal[i].re = m_adFilter[i] * fftOutput[i].re;
623 m_adComplexFftSignal[i].im = m_adFilter[i] * fftOutput[i].im;
626 fftw_complex* ifftOutput = new fftw_complex [ m_nOutputPoints ];
627 fftw_one (m_complexPlanBackward, m_adComplexFftSignal, ifftOutput);
628 for (i = 0; i < m_nSignalPoints * m_iPreinterpolationFactor; i++)
629 output[i] = ifftOutput[i].re;
630 delete [] ifftOutput;
638 * convolve Discrete convolution of two functions
641 * r = convolve (f1, f2, dx, n, np, func_type)
642 * double r Convolved result
643 * double f1[], f2[] Functions to be convolved
644 * double dx Difference between successive x values
645 * int n Array index to center convolution about
646 * int np Number of points in f1 array
647 * int func_type EVEN or ODD or EVEN_AND_ODD function f2
650 * f1 is the projection data, its indices range from 0 to np - 1.
651 * The index for f2, the filter, ranges from -(np-1) to (np-1).
652 * There are 3 ways to handle the negative vertices of f2:
653 * 1. If we know f2 is an EVEN function, then f2[-n] = f2[n].
654 * All filters used in reconstruction are even.
655 * 2. If we know f2 is an ODD function, then f2[-n] = -f2[n]
656 * 3. If f2 is both ODD AND EVEN, then we must store the value of f2
657 * for negative indices. Since f2 must range from -(np-1) to (np-1),
658 * if we add (np - 1) to f2's array index, then f2's index will
659 * range from 0 to 2 * (np - 1), and the origin, x = 0, will be
660 * stored at f2[np-1].
664 ProcessSignal::convolve (const double func[], const double dx, const int n, const int np) const
668 #if UNOPTIMIZED_CONVOLUTION
669 for (int i = 0; i < np; i++)
670 sum += func[i] * m_adFilter[n - i + (np - 1)];
672 double* f2 = m_adFilter + n + (np - 1);
673 for (int i = 0; i < np; i++)
674 sum += *func++ * *f2--;
682 ProcessSignal::convolve (const float func[], const double dx, const int n, const int np) const
686 #if UNOPTIMIZED_CONVOLUTION
687 for (int i = 0; i < np; i++)
688 sum += func[i] * m_adFilter[n - i + (np - 1)];
690 double* f2 = m_adFilter + n + (np - 1);
691 for (int i = 0; i < np; i++)
692 sum += *func++ * *f2--;
700 ProcessSignal::finiteFourierTransform (const double input[], double output[], const int n, int direction)
702 std::complex<double>* complexOutput = new std::complex<double> [n];
704 finiteFourierTransform (input, complexOutput, n, direction);
705 for (int i = 0; i < n; i++)
706 output[i] = complexOutput[i].real();
707 delete [] complexOutput;
711 ProcessSignal::finiteFourierTransform (const double input[], std::complex<double> output[], const int n, int direction)
718 double angleIncrement = direction * 2 * PI / n;
719 for (int i = 0; i < n; i++) {
722 for (int j = 0; j < n; j++) {
723 double angle = i * j * angleIncrement;
724 sumReal += input[j] * cos(angle);
725 sumImag += input[j] * sin(angle);
731 output[i] = std::complex<double> (sumReal, sumImag);
737 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], std::complex<double> output[], const int n, int direction)
744 double angleIncrement = direction * 2 * PI / n;
745 for (int i = 0; i < n; i++) {
746 std::complex<double> sum (0,0);
747 for (int j = 0; j < n; j++) {
748 double angle = i * j * angleIncrement;
749 std::complex<double> exponentTerm (cos(angle), sin(angle));
750 sum += input[j] * exponentTerm;
760 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], double output[], const int n, int direction)
767 double angleIncrement = direction * 2 * PI / n;
768 for (int i = 0; i < n; i++) {
770 for (int j = 0; j < n; j++) {
771 double angle = i * j * angleIncrement;
772 sumReal += input[j].real() * cos(angle) - input[j].imag() * sin(angle);
781 // Table-based routines
784 ProcessSignal::finiteFourierTransform (const double input[], std::complex<double> output[], int direction) const
791 for (int i = 0; i < m_nFilterPoints; i++) {
792 double sumReal = 0, sumImag = 0;
793 for (int j = 0; j < m_nFilterPoints; j++) {
794 int tableIndex = i * j;
796 sumReal += input[j] * m_adFourierCosTable[tableIndex];
797 sumImag += input[j] * m_adFourierSinTable[tableIndex];
799 sumReal += input[j] * m_adFourierCosTable[tableIndex];
800 sumImag -= input[j] * m_adFourierSinTable[tableIndex];
804 sumReal /= m_nFilterPoints;
805 sumImag /= m_nFilterPoints;
807 output[i] = std::complex<double> (sumReal, sumImag);
811 // (a+bi) * (c + di) = (ac - bd) + (ad + bc)i
813 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], std::complex<double> output[], int direction) const
820 for (int i = 0; i < m_nFilterPoints; i++) {
821 double sumReal = 0, sumImag = 0;
822 for (int j = 0; j < m_nFilterPoints; j++) {
823 int tableIndex = i * j;
825 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
826 - input[j].imag() * m_adFourierSinTable[tableIndex];
827 sumImag += input[j].real() * m_adFourierSinTable[tableIndex]
828 + input[j].imag() * m_adFourierCosTable[tableIndex];
830 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
831 - input[j].imag() * -m_adFourierSinTable[tableIndex];
832 sumImag += input[j].real() * -m_adFourierSinTable[tableIndex]
833 + input[j].imag() * m_adFourierCosTable[tableIndex];
837 sumReal /= m_nFilterPoints;
838 sumImag /= m_nFilterPoints;
840 output[i] = std::complex<double> (sumReal, sumImag);
845 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], double output[], int direction) const
852 for (int i = 0; i < m_nFilterPoints; i++) {
854 for (int j = 0; j < m_nFilterPoints; j++) {
855 int tableIndex = i * j;
857 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
858 - input[j].imag() * m_adFourierSinTable[tableIndex];
860 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
861 - input[j].imag() * -m_adFourierSinTable[tableIndex];
865 sumReal /= m_nFilterPoints;