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.18 2001/01/12 14:21:06 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,
284 m_dFilterParam, SignalFilter::DOMAIN_FREQUENCY);
285 m_adFilter = new double [m_nFilterPoints];
286 filter.copyFilterData (m_adFilter, 0, m_nFilterPoints);
288 // This doesn't work!
289 // Need to add filtering for divergent geometries & Frequency/Direct filtering
290 // Jan 2001: Direct seems to work for equilinear and equiangular
291 // however, inverse_fourier doesn't work for equiangular on all versions of CTSim tested
293 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
294 for (i = 0; i < m_nFilterPoints; i++)
295 m_adFilter[i] *= 0.5;
296 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
297 for (i = 0; i < m_nFilterPoints; i++) {
298 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
299 double sinScale = sin (iDetFromZero * m_dSignalInc);
300 if (fabs(sinScale) < 1E-7)
303 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
304 double dScale = 0.5 * sinScale * sinScale;
305 m_adFilter[i] *= dScale;
309 EZPlot* pEZPlot = NULL;
310 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
311 pEZPlot = new EZPlot;
312 pEZPlot->ezset ("title Filter Filter: Natural Order");
313 pEZPlot->ezset ("ylength 0.50");
314 pEZPlot->ezset ("yporigin 0.00");
315 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
316 pEZPlot->plot (pSGP);
319 Fourier::shuffleNaturalToFourierOrder (m_adFilter, m_nFilterPoints);
321 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
322 pEZPlot->ezset ("title Filter Filter: Fourier Order");
323 pEZPlot->ezset ("ylength 0.50");
324 pEZPlot->ezset ("yporigin 0.50");
325 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
326 pEZPlot->plot (pSGP);
330 } else if (m_idFilterGeneration == FILTER_GENERATION_INVERSE_FOURIER) {
331 // calculate number of filter points with zeropadding
332 int nSpatialPoints = 2 * (m_nSignalPoints - 1) + 1;
333 m_dFilterMin = -m_dSignalInc * (m_nSignalPoints - 1);
334 m_dFilterMax = m_dSignalInc * (m_nSignalPoints - 1);
335 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (nSpatialPoints - 1);
336 m_nFilterPoints = nSpatialPoints;
337 if (m_iZeropad > 0) {
338 double logBase2 = log(nSpatialPoints) / log(2);
339 int nextPowerOf2 = static_cast<int>(floor(logBase2));
340 if (logBase2 != floor(logBase2))
342 nextPowerOf2 += (m_iZeropad - 1);
343 m_nFilterPoints = 1 << nextPowerOf2;
345 m_nOutputPoints = m_nFilterPoints * m_iPreinterpolationFactor;
347 if (m_traceLevel >= Trace::TRACE_CONSOLE)
348 std::cout << "nFilterPoints = " << m_nFilterPoints << endl;
350 double* adSpatialFilter = new double [m_nFilterPoints];
351 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, nSpatialPoints, m_dBandwidth,
352 m_dFilterParam, SignalFilter::DOMAIN_SPATIAL);
353 filter.copyFilterData (adSpatialFilter, 0, nSpatialPoints);
355 EZPlot* pEZPlot = NULL;
356 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
357 pEZPlot = new EZPlot;
358 pEZPlot->ezset ("title Spatial Filter: Natural Order");
359 pEZPlot->ezset ("ylength 0.50");
360 pEZPlot->ezset ("yporigin 0.00");
361 pEZPlot->addCurve (adSpatialFilter, nSpatialPoints);
362 pEZPlot->plot (pSGP);
367 // #define PRE_JAN_2001 1
369 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
370 for (i = 0; i < m_nFilterPoints; i++)
371 adSpatialFilter[i] *= 0.5;
372 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
373 for (i = 0; i < m_nFilterPoints; i++) {
374 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
375 double sinScale = sin (iDetFromZero * m_dSignalInc);
376 if (fabs(sinScale) < 1E-7)
379 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
380 double dScale = 0.5 * sinScale * sinScale;
381 adSpatialFilter[i] *= dScale;
384 for (i = nSpatialPoints; i < m_nFilterPoints; i++)
385 adSpatialFilter[i] = 0;
387 m_adFilter = new double [m_nFilterPoints];
388 std::complex<double>* acInverseFilter = new std::complex<double> [m_nFilterPoints];
389 finiteFourierTransform (adSpatialFilter, acInverseFilter, m_nFilterPoints, BACKWARD);
390 delete adSpatialFilter;
391 for (i = 0; i < m_nFilterPoints; i++)
392 m_adFilter[i] = std::abs (acInverseFilter[i]) * m_dSignalInc;
393 delete acInverseFilter;
395 for (i = nSpatialPoints; i < m_nFilterPoints; i++)
396 adSpatialFilter[i] = 0;
398 // for (i = 0; i < m_nFilterPoints; i++)
399 // adSpatialFilter[i] /= m_dSignalInc;
401 std::complex<double>* acInverseFilter = new std::complex<double> [m_nFilterPoints];
402 finiteFourierTransform (adSpatialFilter, acInverseFilter, m_nFilterPoints, FORWARD);
403 delete adSpatialFilter;
404 m_adFilter = new double [m_nFilterPoints];
405 for (i = 0; i < m_nFilterPoints; i++)
406 m_adFilter[i] = std::abs(acInverseFilter[i]);
407 delete acInverseFilter;
409 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
410 for (i = 0; i < m_nFilterPoints; i++)
411 m_adFilter[i] *= 0.5;
412 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
413 for (i = 0; i < m_nFilterPoints; i++) {
414 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
415 double sinScale = sin (iDetFromZero * m_dSignalInc);
416 if (fabs(sinScale) < 1E-7)
419 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
420 double dScale = 0.5 * sinScale * sinScale;
421 m_adFilter[i] *= dScale;
427 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
428 pEZPlot->ezset ("title Spatial Filter: Inverse");
429 pEZPlot->ezset ("ylength 0.50");
430 pEZPlot->ezset ("yporigin 0.50");
431 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
432 pEZPlot->plot (pSGP);
439 // precalculate sin and cosine tables for fourier transform
440 if (m_idFilterMethod == FILTER_METHOD_FOURIER_TABLE) {
441 int nFourier = imax (m_nFilterPoints,m_nOutputPoints) * imax (m_nFilterPoints, m_nOutputPoints) + 1;
442 double angleIncrement = (2. * PI) / m_nFilterPoints;
443 m_adFourierCosTable = new double[ nFourier ];
444 m_adFourierSinTable = new double[ nFourier ];
446 for (i = 0; i < nFourier; i++) {
447 m_adFourierCosTable[i] = cos (angle);
448 m_adFourierSinTable[i] = sin (angle);
449 angle += angleIncrement;
454 if (m_idFilterMethod == FILTER_METHOD_FFTW || m_idFilterMethod == FILTER_METHOD_RFFTW) {
455 for (i = 0; i < m_nFilterPoints; i++) //fftw uses unnormalized fft
456 m_adFilter[i] /= m_nFilterPoints;
459 if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
460 m_realPlanForward = rfftw_create_plan (m_nFilterPoints, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
461 m_realPlanBackward = rfftw_create_plan (m_nOutputPoints, FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE);
462 m_adRealFftInput = new fftw_real [ m_nFilterPoints ];
463 m_adRealFftSignal = new fftw_real [ m_nOutputPoints ];
464 for (i = 0; i < m_nFilterPoints; i++)
465 m_adRealFftInput[i] = 0;
466 } else if (m_idFilterMethod == FILTER_METHOD_FFTW) {
467 m_complexPlanForward = fftw_create_plan (m_nFilterPoints, FFTW_FORWARD, FFTW_ESTIMATE);
468 m_complexPlanBackward = fftw_create_plan (m_nOutputPoints, FFTW_BACKWARD, FFTW_ESTIMATE);
469 m_adComplexFftInput = new fftw_complex [ m_nFilterPoints ];
470 m_adComplexFftSignal = new fftw_complex [ m_nOutputPoints ];
471 for (i = 0; i < m_nFilterPoints; i++)
472 m_adComplexFftInput[i].re = m_adComplexFftInput[i].im = 0;
473 for (i = 0; i < m_nOutputPoints; i++)
474 m_adComplexFftSignal[i].re = m_adComplexFftSignal[i].im = 0;
480 ProcessSignal::~ProcessSignal (void)
482 delete [] m_adFourierSinTable;
483 delete [] m_adFourierCosTable;
484 delete [] m_adFilter;
487 if (m_idFilterMethod == FILTER_METHOD_FFTW) {
488 fftw_destroy_plan(m_complexPlanForward);
489 fftw_destroy_plan(m_complexPlanBackward);
490 delete [] m_adComplexFftInput;
491 delete [] m_adComplexFftSignal;
493 if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
494 rfftw_destroy_plan(m_realPlanForward);
495 rfftw_destroy_plan(m_realPlanBackward);
496 delete [] m_adRealFftInput;
497 delete [] m_adRealFftSignal;
503 ProcessSignal::convertFilterMethodNameToID (const char* const filterMethodName)
505 int fmID = FILTER_METHOD_INVALID;
507 for (int i = 0; i < s_iFilterMethodCount; i++)
508 if (strcasecmp (filterMethodName, s_aszFilterMethodName[i]) == 0) {
517 ProcessSignal::convertFilterMethodIDToName (const int fmID)
519 static const char *name = "";
521 if (fmID >= 0 && fmID < s_iFilterMethodCount)
522 return (s_aszFilterMethodName [fmID]);
528 ProcessSignal::convertFilterMethodIDToTitle (const int fmID)
530 static const char *title = "";
532 if (fmID >= 0 && fmID < s_iFilterMethodCount)
533 return (s_aszFilterMethodTitle [fmID]);
540 ProcessSignal::convertFilterGenerationNameToID (const char* const fgName)
542 int fgID = FILTER_GENERATION_INVALID;
544 for (int i = 0; i < s_iFilterGenerationCount; i++)
545 if (strcasecmp (fgName, s_aszFilterGenerationName[i]) == 0) {
554 ProcessSignal::convertFilterGenerationIDToName (const int fgID)
556 static const char *name = "";
558 if (fgID >= 0 && fgID < s_iFilterGenerationCount)
559 return (s_aszFilterGenerationName [fgID]);
565 ProcessSignal::convertFilterGenerationIDToTitle (const int fgID)
567 static const char *name = "";
569 if (fgID >= 0 && fgID < s_iFilterGenerationCount)
570 return (s_aszFilterGenerationTitle [fgID]);
576 ProcessSignal::filterSignal (const float constInput[], double output[]) const
578 double* input = new double [m_nSignalPoints];
580 for (i = 0; i < m_nSignalPoints; i++)
581 input[i] = constInput[i];
583 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
584 for (int i = 0; i < m_nSignalPoints; i++) {
585 int iDetFromCenter = i - (m_nSignalPoints / 2);
586 input[i] *= m_dFocalLength / sqrt (m_dFocalLength * m_dFocalLength + iDetFromCenter * iDetFromCenter * m_dSignalInc * m_dSignalInc);
588 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
589 for (int i = 0; i < m_nSignalPoints; i++) {
590 int iDetFromCenter = i - (m_nSignalPoints / 2);
591 input[i] *= m_dFocalLength * cos (iDetFromCenter * m_dSignalInc);
594 if (m_idFilterMethod == FILTER_METHOD_CONVOLUTION) {
595 for (i = 0; i < m_nSignalPoints; i++)
596 output[i] = convolve (input, m_dSignalInc, i, m_nSignalPoints);
597 } else if (m_idFilterMethod == FILTER_METHOD_FOURIER) {
598 double* inputSignal = new double [m_nFilterPoints];
599 for (i = 0; i < m_nSignalPoints; i++)
600 inputSignal[i] = input[i];
601 for (i = m_nSignalPoints; i < m_nFilterPoints; i++)
602 inputSignal[i] = 0; // zeropad
603 std::complex<double>* fftSignal = new std::complex<double> [m_nFilterPoints];
604 finiteFourierTransform (inputSignal, fftSignal, m_nFilterPoints, FORWARD);
606 for (i = 0; i < m_nFilterPoints; i++)
607 fftSignal[i] *= m_adFilter[i];
608 double* inverseFourier = new double [m_nFilterPoints];
609 finiteFourierTransform (fftSignal, inverseFourier, m_nFilterPoints, BACKWARD);
611 for (i = 0; i < m_nSignalPoints; i++)
612 output[i] = inverseFourier[i];
613 delete inverseFourier;
614 } else if (m_idFilterMethod == FILTER_METHOD_FOURIER_TABLE) {
615 double* inputSignal = new double [m_nFilterPoints];
616 for (i = 0; i < m_nSignalPoints; i++)
617 inputSignal[i] = input[i];
618 for (i = m_nSignalPoints; i < m_nFilterPoints; i++)
619 inputSignal[i] = 0; // zeropad
620 std::complex<double>* fftSignal = new std::complex<double> [m_nFilterPoints];
621 finiteFourierTransform (inputSignal, fftSignal, FORWARD);
623 for (i = 0; i < m_nFilterPoints; i++)
624 fftSignal[i] *= m_adFilter[i];
625 double* inverseFourier = new double [m_nFilterPoints];
626 finiteFourierTransform (fftSignal, inverseFourier, BACKWARD);
628 for (i = 0; i < m_nSignalPoints; i++)
629 output[i] = inverseFourier[i];
630 delete inverseFourier;
633 else if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
634 for (i = 0; i < m_nSignalPoints; i++)
635 m_adRealFftInput[i] = input[i];
637 fftw_real* fftOutput = new fftw_real [ m_nFilterPoints ];
638 rfftw_one (m_realPlanForward, m_adRealFftInput, fftOutput);
639 for (i = 0; i < m_nFilterPoints; i++)
640 m_adRealFftSignal[i] = m_adFilter[i] * fftOutput[i];
642 for (i = m_nFilterPoints; i < m_nOutputPoints; i++)
643 m_adRealFftSignal[i] = 0;
645 fftw_real* ifftOutput = new fftw_real [ m_nOutputPoints ];
646 rfftw_one (m_realPlanBackward, m_adRealFftSignal, ifftOutput);
647 for (i = 0; i < m_nSignalPoints * m_iPreinterpolationFactor; i++)
648 output[i] = ifftOutput[i];
649 delete [] ifftOutput;
650 } else if (m_idFilterMethod == FILTER_METHOD_FFTW) {
651 for (i = 0; i < m_nSignalPoints; i++)
652 m_adComplexFftInput[i].re = input[i];
654 fftw_complex* fftOutput = new fftw_complex [ m_nFilterPoints ];
655 fftw_one (m_complexPlanForward, m_adComplexFftInput, fftOutput);
656 for (i = 0; i < m_nFilterPoints; i++) {
657 m_adComplexFftSignal[i].re = m_adFilter[i] * fftOutput[i].re;
658 m_adComplexFftSignal[i].im = m_adFilter[i] * fftOutput[i].im;
661 fftw_complex* ifftOutput = new fftw_complex [ m_nOutputPoints ];
662 fftw_one (m_complexPlanBackward, m_adComplexFftSignal, ifftOutput);
663 for (i = 0; i < m_nSignalPoints * m_iPreinterpolationFactor; i++)
664 output[i] = ifftOutput[i].re;
665 delete [] ifftOutput;
673 * convolve Discrete convolution of two functions
676 * r = convolve (f1, f2, dx, n, np, func_type)
677 * double r Convolved result
678 * double f1[], f2[] Functions to be convolved
679 * double dx Difference between successive x values
680 * int n Array index to center convolution about
681 * int np Number of points in f1 array
682 * int func_type EVEN or ODD or EVEN_AND_ODD function f2
685 * f1 is the projection data, its indices range from 0 to np - 1.
686 * The index for f2, the filter, ranges from -(np-1) to (np-1).
687 * There are 3 ways to handle the negative vertices of f2:
688 * 1. If we know f2 is an EVEN function, then f2[-n] = f2[n].
689 * All filters used in reconstruction are even.
690 * 2. If we know f2 is an ODD function, then f2[-n] = -f2[n]
691 * 3. If f2 is both ODD AND EVEN, then we must store the value of f2
692 * for negative indices. Since f2 must range from -(np-1) to (np-1),
693 * if we add (np - 1) to f2's array index, then f2's index will
694 * range from 0 to 2 * (np - 1), and the origin, x = 0, will be
695 * stored at f2[np-1].
699 ProcessSignal::convolve (const double func[], const double dx, const int n, const int np) const
703 #if UNOPTIMIZED_CONVOLUTION
704 for (int i = 0; i < np; i++)
705 sum += func[i] * m_adFilter[n - i + (np - 1)];
707 double* f2 = m_adFilter + n + (np - 1);
708 for (int i = 0; i < np; i++)
709 sum += *func++ * *f2--;
717 ProcessSignal::convolve (const float func[], const double dx, const int n, const int np) const
721 #if UNOPTIMIZED_CONVOLUTION
722 for (int i = 0; i < np; i++)
723 sum += func[i] * m_adFilter[n - i + (np - 1)];
725 double* f2 = m_adFilter + n + (np - 1);
726 for (int i = 0; i < np; i++)
727 sum += *func++ * *f2--;
735 ProcessSignal::finiteFourierTransform (const double input[], double output[], const int n, int direction)
737 std::complex<double>* complexOutput = new std::complex<double> [n];
739 finiteFourierTransform (input, complexOutput, n, direction);
740 for (int i = 0; i < n; i++)
741 output[i] = complexOutput[i].real();
742 delete [] complexOutput;
746 ProcessSignal::finiteFourierTransform (const double input[], std::complex<double> output[], const int n, int direction)
753 double angleIncrement = direction * 2 * PI / n;
754 for (int i = 0; i < n; i++) {
757 for (int j = 0; j < n; j++) {
758 double angle = i * j * angleIncrement;
759 sumReal += input[j] * cos(angle);
760 sumImag += input[j] * sin(angle);
766 output[i] = std::complex<double> (sumReal, sumImag);
772 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], std::complex<double> output[], const int n, int direction)
779 double angleIncrement = direction * 2 * PI / n;
780 for (int i = 0; i < n; i++) {
781 std::complex<double> sum (0,0);
782 for (int j = 0; j < n; j++) {
783 double angle = i * j * angleIncrement;
784 std::complex<double> exponentTerm (cos(angle), sin(angle));
785 sum += input[j] * exponentTerm;
795 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], double output[], const int n, int direction)
802 double angleIncrement = direction * 2 * PI / n;
803 for (int i = 0; i < n; i++) {
805 for (int j = 0; j < n; j++) {
806 double angle = i * j * angleIncrement;
807 sumReal += input[j].real() * cos(angle) - input[j].imag() * sin(angle);
816 // Table-based routines
819 ProcessSignal::finiteFourierTransform (const double input[], std::complex<double> output[], int direction) const
826 for (int i = 0; i < m_nFilterPoints; i++) {
827 double sumReal = 0, sumImag = 0;
828 for (int j = 0; j < m_nFilterPoints; j++) {
829 int tableIndex = i * j;
831 sumReal += input[j] * m_adFourierCosTable[tableIndex];
832 sumImag += input[j] * m_adFourierSinTable[tableIndex];
834 sumReal += input[j] * m_adFourierCosTable[tableIndex];
835 sumImag -= input[j] * m_adFourierSinTable[tableIndex];
839 sumReal /= m_nFilterPoints;
840 sumImag /= m_nFilterPoints;
842 output[i] = std::complex<double> (sumReal, sumImag);
846 // (a+bi) * (c + di) = (ac - bd) + (ad + bc)i
848 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], std::complex<double> output[], int direction) const
855 for (int i = 0; i < m_nFilterPoints; i++) {
856 double sumReal = 0, sumImag = 0;
857 for (int j = 0; j < m_nFilterPoints; j++) {
858 int tableIndex = i * j;
860 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
861 - input[j].imag() * m_adFourierSinTable[tableIndex];
862 sumImag += input[j].real() * m_adFourierSinTable[tableIndex]
863 + input[j].imag() * m_adFourierCosTable[tableIndex];
865 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
866 - input[j].imag() * -m_adFourierSinTable[tableIndex];
867 sumImag += input[j].real() * -m_adFourierSinTable[tableIndex]
868 + input[j].imag() * m_adFourierCosTable[tableIndex];
872 sumReal /= m_nFilterPoints;
873 sumImag /= m_nFilterPoints;
875 output[i] = std::complex<double> (sumReal, sumImag);
880 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], double output[], int direction) const
887 for (int i = 0; i < m_nFilterPoints; i++) {
889 for (int j = 0; j < m_nFilterPoints; j++) {
890 int tableIndex = i * j;
892 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
893 - input[j].imag() * m_adFourierSinTable[tableIndex];
895 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
896 - input[j].imag() * -m_adFourierSinTable[tableIndex];
900 sumReal /= m_nFilterPoints;