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.19 2001/01/12 16:41:56 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 ******************************************************************************/
31 #include "../src/dlgezplot.h"
34 // FilterMethod ID/Names
35 const int ProcessSignal::FILTER_METHOD_INVALID = -1;
36 const int ProcessSignal::FILTER_METHOD_CONVOLUTION = 0;
37 const int ProcessSignal::FILTER_METHOD_FOURIER = 1;
38 const int ProcessSignal::FILTER_METHOD_FOURIER_TABLE = 2;
39 const int ProcessSignal::FILTER_METHOD_FFT = 3;
41 const int ProcessSignal::FILTER_METHOD_FFTW = 4;
42 const int ProcessSignal::FILTER_METHOD_RFFTW =5 ;
44 const char* ProcessSignal::s_aszFilterMethodName[] = {
54 const char* ProcessSignal::s_aszFilterMethodTitle[] = {
57 {"Fouier Trigometric Table"},
61 {"Real/Half-Complex FFTW"},
64 const int ProcessSignal::s_iFilterMethodCount = sizeof(s_aszFilterMethodName) / sizeof(const char*);
66 // FilterGeneration ID/Names
67 const int ProcessSignal::FILTER_GENERATION_INVALID = -1;
68 const int ProcessSignal::FILTER_GENERATION_DIRECT = 0;
69 const int ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER = 1;
70 const char* ProcessSignal::s_aszFilterGenerationName[] = {
74 const char* ProcessSignal::s_aszFilterGenerationTitle[] = {
78 const int ProcessSignal::s_iFilterGenerationCount = sizeof(s_aszFilterGenerationName) / sizeof(const char*);
81 // CLASS IDENTIFICATION
84 ProcessSignal::ProcessSignal (const char* szFilterName, const char* szFilterMethodName, double dBandwidth,
85 double dSignalIncrement, int nSignalPoints, double dFilterParam, const char* szDomainName,
86 const char* szFilterGenerationName, int iZeropad, int iPreinterpolationFactor, int iTraceLevel,
87 int iGeometry, double dFocalLength, SGP* pSGP)
88 : m_adFourierCosTable(NULL), m_adFourierSinTable(NULL), m_adFilter(NULL), m_fail(false)
90 m_idFilterMethod = convertFilterMethodNameToID (szFilterMethodName);
91 if (m_idFilterMethod == FILTER_METHOD_INVALID) {
93 m_failMessage = "Invalid filter method name ";
94 m_failMessage += szFilterMethodName;
97 m_idFilterGeneration = convertFilterGenerationNameToID (szFilterGenerationName);
98 if (m_idFilterGeneration == FILTER_GENERATION_INVALID) {
100 m_failMessage = "Invalid frequency filter name ";
101 m_failMessage += szFilterGenerationName;
104 m_idFilter = SignalFilter::convertFilterNameToID (szFilterName);
105 if (m_idFilter == SignalFilter::FILTER_INVALID) {
107 m_failMessage = "Invalid Filter name ";
108 m_failMessage += szFilterName;
111 m_idDomain = SignalFilter::convertDomainNameToID (szDomainName);
112 if (m_idDomain == SignalFilter::DOMAIN_INVALID) {
114 m_failMessage = "Invalid domain name ";
115 m_failMessage += szDomainName;
119 init (m_idFilter, m_idFilterMethod, dBandwidth, dSignalIncrement, nSignalPoints, dFilterParam, m_idDomain,
120 m_idFilterGeneration, iZeropad, iPreinterpolationFactor, iTraceLevel, iGeometry, dFocalLength, pSGP);
125 ProcessSignal::init (const int idFilter, const int idFilterMethod, double dBandwidth, double dSignalIncrement,
126 int nSignalPoints, double dFilterParam, const int idDomain, const int idFilterGeneration,
127 const int iZeropad, const int iPreinterpolationFactor, int iTraceLevel, int iGeometry,
128 double dFocalLength, SGP* pSGP)
131 m_idFilter = idFilter;
132 m_idDomain = idDomain;
133 m_idFilterMethod = idFilterMethod;
134 m_idFilterGeneration = idFilterGeneration;
135 m_idGeometry = iGeometry;
136 m_dFocalLength = dFocalLength;
138 if (m_idFilter == SignalFilter::FILTER_INVALID || m_idDomain == SignalFilter::DOMAIN_INVALID || m_idFilterMethod == FILTER_METHOD_INVALID || m_idFilterGeneration == FILTER_GENERATION_INVALID) {
142 m_traceLevel = iTraceLevel;
143 m_nameFilterMethod = convertFilterMethodIDToName (m_idFilterMethod);
144 m_nameFilterGeneration = convertFilterGenerationIDToName (m_idFilterGeneration);
145 m_dBandwidth = dBandwidth;
146 m_nSignalPoints = nSignalPoints;
147 m_dSignalInc = dSignalIncrement;
148 m_dFilterParam = dFilterParam;
149 m_iZeropad = iZeropad;
150 m_iPreinterpolationFactor = iPreinterpolationFactor;
152 // scale signalInc/BW to signalInc/2 to adjust for imaginary detector
153 // through origin of phantom rather than 2 times distance to detector,
154 // see Kak-Slaney Fig 3.22, for Collinear diagram
155 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
160 if (m_idFilterMethod == FILTER_METHOD_FFT) {
162 m_idFilterMethod = FILTER_METHOD_RFFTW;
165 m_failMessage = "FFT not yet implemented";
170 bool m_bFrequencyFiltering = true;
171 if (m_idFilterMethod == FILTER_METHOD_CONVOLUTION)
172 m_bFrequencyFiltering = false;
174 // Spatial-based filtering
175 if (! m_bFrequencyFiltering) {
177 if (m_idFilterGeneration == FILTER_GENERATION_DIRECT) {
178 m_nFilterPoints = 2 * (m_nSignalPoints - 1) + 1;
179 m_dFilterMin = -m_dSignalInc * (m_nSignalPoints - 1);
180 m_dFilterMax = m_dSignalInc * (m_nSignalPoints - 1);
181 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
182 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, m_nFilterPoints, m_dBandwidth, m_dFilterParam, SignalFilter::DOMAIN_SPATIAL);
183 m_adFilter = new double[ m_nFilterPoints ];
184 filter.copyFilterData (m_adFilter, 0, m_nFilterPoints);
185 } else if (m_idFilterGeneration == FILTER_GENERATION_INVERSE_FOURIER) {
186 m_nFilterPoints = 2 * (m_nSignalPoints - 1) + 1;
187 m_dFilterMin = -1. / (2 * m_dSignalInc);
188 m_dFilterMax = 1. / (2 * m_dSignalInc);
189 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
190 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, m_nFilterPoints, m_dBandwidth, m_dFilterParam, SignalFilter::DOMAIN_FREQUENCY);
191 m_adFilter = new double[ m_nFilterPoints ];
192 double* adFrequencyFilter = new double [m_nFilterPoints];
193 filter.copyFilterData (adFrequencyFilter, 0, m_nFilterPoints);
195 EZPlot* pEZPlot = NULL;
196 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
197 pEZPlot = new EZPlot ();
198 pEZPlot->ezset ("title Filter Response: Natural Order");
199 pEZPlot->ezset ("ylength 0.25");
200 pEZPlot->addCurve (adFrequencyFilter, m_nFilterPoints);
201 pEZPlot->plot (pSGP);
204 Fourier::shuffleNaturalToFourierOrder (adFrequencyFilter, m_nFilterPoints);
206 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
207 pEZPlot->ezset ("title Filter Response: Fourier Order");
208 pEZPlot->ezset ("ylength 0.25");
209 pEZPlot->ezset ("yporigin 0.25");
210 pEZPlot->addCurve (adFrequencyFilter, m_nFilterPoints);
211 pEZPlot->plot (pSGP);
214 ProcessSignal::finiteFourierTransform (adFrequencyFilter, m_adFilter, m_nFilterPoints, FORWARD);
215 delete adFrequencyFilter;
217 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
218 pEZPlot->ezset ("title Inverse Fourier Frequency: Fourier Order");
219 pEZPlot->ezset ("ylength 0.25");
220 pEZPlot->ezset ("yporigin 0.50");
221 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
222 pEZPlot->plot (pSGP);
225 Fourier::shuffleFourierToNaturalOrder (m_adFilter, m_nFilterPoints);
227 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
228 pEZPlot->ezset ("title Inverse Fourier Frequency: Natural Order");
229 pEZPlot->ezset ("ylength 0.25");
230 pEZPlot->ezset ("yporigin 0.75");
231 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
232 pEZPlot->plot (pSGP);
236 for (i = 0; i < m_nFilterPoints; i++) {
237 m_adFilter[i] /= m_dSignalInc;
240 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
241 for (i = 0; i < m_nFilterPoints; i++)
242 m_adFilter[i] *= 0.5;
243 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
244 for (i = 0; i < m_nFilterPoints; i++) {
245 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
246 double sinScale = sin (iDetFromZero * m_dSignalInc);
247 if (fabs(sinScale) < 1E-7)
250 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
251 double dScale = 0.5 * sinScale * sinScale;
252 m_adFilter[i] *= dScale;
255 } // if (spatial filtering)
257 else if (m_bFrequencyFiltering) { // Frequency-based filtering
259 if (m_idFilterGeneration == FILTER_GENERATION_DIRECT) {
260 // calculate number of filter points with zeropadding
261 m_nFilterPoints = m_nSignalPoints;
262 if (m_iZeropad > 0) {
263 double logBase2 = log(m_nFilterPoints) / log(2);
264 int nextPowerOf2 = static_cast<int>(floor(logBase2));
265 if (logBase2 != floor(logBase2))
267 nextPowerOf2 += (m_iZeropad - 1);
268 m_nFilterPoints = 1 << nextPowerOf2;
270 if (m_traceLevel >= Trace::TRACE_CONSOLE)
271 std::cout << "nFilterPoints = " << m_nFilterPoints << endl;
274 m_nOutputPoints = m_nFilterPoints * m_iPreinterpolationFactor;
276 if (m_nFilterPoints % 2) { // Odd
277 m_dFilterMin = -1. / (2 * m_dSignalInc);
278 m_dFilterMax = 1. / (2 * m_dSignalInc);
279 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
281 m_dFilterMin = -1. / (2 * m_dSignalInc);
282 m_dFilterMax = 1. / (2 * m_dSignalInc);
283 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / m_nFilterPoints;
284 m_dFilterMax -= m_dFilterInc;
287 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, m_nFilterPoints, m_dBandwidth,
288 m_dFilterParam, SignalFilter::DOMAIN_FREQUENCY);
289 m_adFilter = new double [m_nFilterPoints];
290 filter.copyFilterData (m_adFilter, 0, m_nFilterPoints);
292 // This doesn't work!
293 // Need to add filtering for divergent geometries & Frequency/Direct filtering
294 // Jan 2001: Direct seems to work for equilinear and equiangular
295 // however, inverse_fourier doesn't work for equiangular on all versions of CTSim tested
297 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
298 for (i = 0; i < m_nFilterPoints; i++)
299 m_adFilter[i] *= 0.5;
300 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
301 for (i = 0; i < m_nFilterPoints; i++) {
302 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
303 double sinScale = sin (iDetFromZero * m_dSignalInc);
304 if (fabs(sinScale) < 1E-7)
307 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
308 double dScale = 0.5 * sinScale * sinScale;
309 m_adFilter[i] *= dScale;
313 EZPlot* pEZPlot = NULL;
314 if (pSGP && m_traceLevel >= Trace::TRACE_PLOT) {
315 pEZPlot = new EZPlot;
316 pEZPlot->ezset ("title Filter Filter: Natural Order");
317 pEZPlot->ezset ("ylength 0.50");
318 pEZPlot->ezset ("yporigin 0.00");
319 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
320 pEZPlot->plot (pSGP);
323 Fourier::shuffleNaturalToFourierOrder (m_adFilter, m_nFilterPoints);
325 if (pEZPlot && m_traceLevel >= Trace::TRACE_PLOT) {
326 pEZPlot->ezset ("title Filter Filter: Fourier Order");
327 pEZPlot->ezset ("ylength 0.50");
328 pEZPlot->ezset ("yporigin 0.50");
329 pEZPlot->addCurve (m_adFilter, m_nFilterPoints);
330 pEZPlot->plot (pSGP);
334 } else if (m_idFilterGeneration == FILTER_GENERATION_INVERSE_FOURIER) {
335 // calculate number of filter points with zeropadding
336 int nSpatialPoints = 2 * (m_nSignalPoints - 1) + 1;
337 m_dFilterMin = -m_dSignalInc * (m_nSignalPoints - 1);
338 m_dFilterMax = m_dSignalInc * (m_nSignalPoints - 1);
339 m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (nSpatialPoints - 1);
340 m_nFilterPoints = nSpatialPoints;
341 if (m_iZeropad > 0) {
342 double logBase2 = log(nSpatialPoints) / log(2);
343 int nextPowerOf2 = static_cast<int>(floor(logBase2));
344 if (logBase2 != floor(logBase2))
346 nextPowerOf2 += (m_iZeropad - 1);
347 m_nFilterPoints = 1 << nextPowerOf2;
349 m_nOutputPoints = m_nFilterPoints * m_iPreinterpolationFactor;
351 if (m_traceLevel >= Trace::TRACE_CONSOLE)
352 std::cout << "nFilterPoints = " << m_nFilterPoints << endl;
354 double* adSpatialFilter = new double [m_nFilterPoints];
355 SignalFilter filter (m_idFilter, m_dFilterMin, m_dFilterMax, nSpatialPoints, m_dBandwidth,
356 m_dFilterParam, SignalFilter::DOMAIN_SPATIAL);
357 filter.copyFilterData (adSpatialFilter, 0, nSpatialPoints);
358 #if defined(HAVE_WXWINDOWS) && defined(DEBUG)
359 EZPlotDialog pEZPlotDlg = NULL;
360 if (g_bRunningWXWindows && m_traceLevel > 0) {
361 pEZPlotDlg = new EZPlotDialog;
362 pEZPlot->getEZPlot()->ezset ("title Spatial Filter: Natural Order");
363 pEZPlot->getEZPlot()->ezset ("ylength 0.50");
364 pEZPlot->getEZPlot()->ezset ("yporigin 0.00");
365 pEZPlot->getEZPlot()->addCurve (adSpatialFilter, nSpatialPoints);
369 // #define PRE_JAN_2001 1
371 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
372 for (i = 0; i < m_nFilterPoints; i++)
373 adSpatialFilter[i] *= 0.5;
374 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
375 for (i = 0; i < m_nFilterPoints; i++) {
376 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
377 double sinScale = sin (iDetFromZero * m_dSignalInc);
378 if (fabs(sinScale) < 1E-7)
381 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
382 double dScale = 0.5 * sinScale * sinScale;
383 adSpatialFilter[i] *= dScale;
386 for (i = nSpatialPoints; i < m_nFilterPoints; i++)
387 adSpatialFilter[i] = 0;
389 m_adFilter = new double [m_nFilterPoints];
390 std::complex<double>* acInverseFilter = new std::complex<double> [m_nFilterPoints];
391 finiteFourierTransform (adSpatialFilter, acInverseFilter, m_nFilterPoints, BACKWARD);
392 delete adSpatialFilter;
393 for (i = 0; i < m_nFilterPoints; i++)
394 m_adFilter[i] = std::abs (acInverseFilter[i]) * m_dSignalInc;
395 delete acInverseFilter;
397 for (i = nSpatialPoints; i < m_nFilterPoints; i++)
398 adSpatialFilter[i] = 0;
400 // for (i = 0; i < m_nFilterPoints; i++)
401 // adSpatialFilter[i] /= m_dSignalInc;
403 std::complex<double>* acInverseFilter = new std::complex<double> [m_nFilterPoints];
404 finiteFourierTransform (adSpatialFilter, acInverseFilter, m_nFilterPoints, FORWARD);
405 delete adSpatialFilter;
406 m_adFilter = new double [m_nFilterPoints];
407 for (i = 0; i < m_nFilterPoints; i++)
408 m_adFilter[i] = std::abs(acInverseFilter[i]);
409 delete acInverseFilter;
411 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
412 for (i = 0; i < m_nFilterPoints; i++)
413 m_adFilter[i] *= 0.5;
414 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
415 for (i = 0; i < m_nFilterPoints; i++) {
416 int iDetFromZero = i - ((m_nFilterPoints - 1) / 2);
417 double sinScale = sin (iDetFromZero * m_dSignalInc);
418 if (fabs(sinScale) < 1E-7)
421 sinScale = (iDetFromZero * m_dSignalInc) / sinScale;
422 double dScale = 0.5 * sinScale * sinScale;
423 m_adFilter[i] *= dScale;
428 #if defined(HAVE_WXWINDOWS) && defined(DEBUG)
429 if (g_bRunningWXWindows && pEZPlotDlg && m_traceLevel > 0) {
430 pEZPlotDlg->getEZPlot()->ezset ("title Spatial Filter: Inverse");
431 pEZPlotDlg->getEZPlot()->ezset ("ylength 0.50");
432 pEZPlotDlg->getEZPlot()->ezset ("yporigin 0.50");
433 pEZPlotDlg->getEZPlot()->addCurve (m_adFilter, m_nFilterPoints);
434 pEZPlotDlg->ShowModal();
441 // precalculate sin and cosine tables for fourier transform
442 if (m_idFilterMethod == FILTER_METHOD_FOURIER_TABLE) {
443 int nFourier = imax (m_nFilterPoints,m_nOutputPoints) * imax (m_nFilterPoints, m_nOutputPoints) + 1;
444 double angleIncrement = (2. * PI) / m_nFilterPoints;
445 m_adFourierCosTable = new double[ nFourier ];
446 m_adFourierSinTable = new double[ nFourier ];
448 for (i = 0; i < nFourier; i++) {
449 m_adFourierCosTable[i] = cos (angle);
450 m_adFourierSinTable[i] = sin (angle);
451 angle += angleIncrement;
456 if (m_idFilterMethod == FILTER_METHOD_FFTW || m_idFilterMethod == FILTER_METHOD_RFFTW) {
457 for (i = 0; i < m_nFilterPoints; i++) //fftw uses unnormalized fft
458 m_adFilter[i] /= m_nFilterPoints;
461 if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
462 m_realPlanForward = rfftw_create_plan (m_nFilterPoints, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
463 m_realPlanBackward = rfftw_create_plan (m_nOutputPoints, FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE);
464 m_adRealFftInput = new fftw_real [ m_nFilterPoints ];
465 m_adRealFftSignal = new fftw_real [ m_nOutputPoints ];
466 for (i = 0; i < m_nFilterPoints; i++)
467 m_adRealFftInput[i] = 0;
468 } else if (m_idFilterMethod == FILTER_METHOD_FFTW) {
469 m_complexPlanForward = fftw_create_plan (m_nFilterPoints, FFTW_FORWARD, FFTW_ESTIMATE);
470 m_complexPlanBackward = fftw_create_plan (m_nOutputPoints, FFTW_BACKWARD, FFTW_ESTIMATE);
471 m_adComplexFftInput = new fftw_complex [ m_nFilterPoints ];
472 m_adComplexFftSignal = new fftw_complex [ m_nOutputPoints ];
473 for (i = 0; i < m_nFilterPoints; i++)
474 m_adComplexFftInput[i].re = m_adComplexFftInput[i].im = 0;
475 for (i = 0; i < m_nOutputPoints; i++)
476 m_adComplexFftSignal[i].re = m_adComplexFftSignal[i].im = 0;
482 ProcessSignal::~ProcessSignal (void)
484 delete [] m_adFourierSinTable;
485 delete [] m_adFourierCosTable;
486 delete [] m_adFilter;
489 if (m_idFilterMethod == FILTER_METHOD_FFTW) {
490 fftw_destroy_plan(m_complexPlanForward);
491 fftw_destroy_plan(m_complexPlanBackward);
492 delete [] m_adComplexFftInput;
493 delete [] m_adComplexFftSignal;
495 if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
496 rfftw_destroy_plan(m_realPlanForward);
497 rfftw_destroy_plan(m_realPlanBackward);
498 delete [] m_adRealFftInput;
499 delete [] m_adRealFftSignal;
505 ProcessSignal::convertFilterMethodNameToID (const char* const filterMethodName)
507 int fmID = FILTER_METHOD_INVALID;
509 for (int i = 0; i < s_iFilterMethodCount; i++)
510 if (strcasecmp (filterMethodName, s_aszFilterMethodName[i]) == 0) {
519 ProcessSignal::convertFilterMethodIDToName (const int fmID)
521 static const char *name = "";
523 if (fmID >= 0 && fmID < s_iFilterMethodCount)
524 return (s_aszFilterMethodName [fmID]);
530 ProcessSignal::convertFilterMethodIDToTitle (const int fmID)
532 static const char *title = "";
534 if (fmID >= 0 && fmID < s_iFilterMethodCount)
535 return (s_aszFilterMethodTitle [fmID]);
542 ProcessSignal::convertFilterGenerationNameToID (const char* const fgName)
544 int fgID = FILTER_GENERATION_INVALID;
546 for (int i = 0; i < s_iFilterGenerationCount; i++)
547 if (strcasecmp (fgName, s_aszFilterGenerationName[i]) == 0) {
556 ProcessSignal::convertFilterGenerationIDToName (const int fgID)
558 static const char *name = "";
560 if (fgID >= 0 && fgID < s_iFilterGenerationCount)
561 return (s_aszFilterGenerationName [fgID]);
567 ProcessSignal::convertFilterGenerationIDToTitle (const int fgID)
569 static const char *name = "";
571 if (fgID >= 0 && fgID < s_iFilterGenerationCount)
572 return (s_aszFilterGenerationTitle [fgID]);
578 ProcessSignal::filterSignal (const float constInput[], double output[]) const
580 double* input = new double [m_nSignalPoints];
582 for (i = 0; i < m_nSignalPoints; i++)
583 input[i] = constInput[i];
585 if (m_idGeometry == Scanner::GEOMETRY_EQUILINEAR) {
586 for (int i = 0; i < m_nSignalPoints; i++) {
587 int iDetFromCenter = i - (m_nSignalPoints / 2);
588 input[i] *= m_dFocalLength / sqrt (m_dFocalLength * m_dFocalLength + iDetFromCenter * iDetFromCenter * m_dSignalInc * m_dSignalInc);
590 } else if (m_idGeometry == Scanner::GEOMETRY_EQUIANGULAR) {
591 for (int i = 0; i < m_nSignalPoints; i++) {
592 int iDetFromCenter = i - (m_nSignalPoints / 2);
593 input[i] *= m_dFocalLength * cos (iDetFromCenter * m_dSignalInc);
596 if (m_idFilterMethod == FILTER_METHOD_CONVOLUTION) {
597 for (i = 0; i < m_nSignalPoints; i++)
598 output[i] = convolve (input, m_dSignalInc, i, m_nSignalPoints);
599 } else if (m_idFilterMethod == FILTER_METHOD_FOURIER) {
600 double* inputSignal = new double [m_nFilterPoints];
601 for (i = 0; i < m_nSignalPoints; i++)
602 inputSignal[i] = input[i];
603 for (i = m_nSignalPoints; i < m_nFilterPoints; i++)
604 inputSignal[i] = 0; // zeropad
605 std::complex<double>* fftSignal = new std::complex<double> [m_nFilterPoints];
606 finiteFourierTransform (inputSignal, fftSignal, m_nFilterPoints, FORWARD);
608 for (i = 0; i < m_nFilterPoints; i++)
609 fftSignal[i] *= m_adFilter[i];
610 double* inverseFourier = new double [m_nFilterPoints];
611 finiteFourierTransform (fftSignal, inverseFourier, m_nFilterPoints, BACKWARD);
613 for (i = 0; i < m_nSignalPoints; i++)
614 output[i] = inverseFourier[i];
615 delete inverseFourier;
616 } else if (m_idFilterMethod == FILTER_METHOD_FOURIER_TABLE) {
617 double* inputSignal = new double [m_nFilterPoints];
618 for (i = 0; i < m_nSignalPoints; i++)
619 inputSignal[i] = input[i];
620 for (i = m_nSignalPoints; i < m_nFilterPoints; i++)
621 inputSignal[i] = 0; // zeropad
622 std::complex<double>* fftSignal = new std::complex<double> [m_nFilterPoints];
623 finiteFourierTransform (inputSignal, fftSignal, FORWARD);
625 for (i = 0; i < m_nFilterPoints; i++)
626 fftSignal[i] *= m_adFilter[i];
627 double* inverseFourier = new double [m_nFilterPoints];
628 finiteFourierTransform (fftSignal, inverseFourier, BACKWARD);
630 for (i = 0; i < m_nSignalPoints; i++)
631 output[i] = inverseFourier[i];
632 delete inverseFourier;
635 else if (m_idFilterMethod == FILTER_METHOD_RFFTW) {
636 for (i = 0; i < m_nSignalPoints; i++)
637 m_adRealFftInput[i] = input[i];
639 fftw_real* fftOutput = new fftw_real [ m_nFilterPoints ];
640 rfftw_one (m_realPlanForward, m_adRealFftInput, fftOutput);
641 for (i = 0; i < m_nFilterPoints; i++)
642 m_adRealFftSignal[i] = m_adFilter[i] * fftOutput[i];
644 for (i = m_nFilterPoints; i < m_nOutputPoints; i++)
645 m_adRealFftSignal[i] = 0;
647 fftw_real* ifftOutput = new fftw_real [ m_nOutputPoints ];
648 rfftw_one (m_realPlanBackward, m_adRealFftSignal, ifftOutput);
649 for (i = 0; i < m_nSignalPoints * m_iPreinterpolationFactor; i++)
650 output[i] = ifftOutput[i];
651 delete [] ifftOutput;
652 } else if (m_idFilterMethod == FILTER_METHOD_FFTW) {
653 for (i = 0; i < m_nSignalPoints; i++)
654 m_adComplexFftInput[i].re = input[i];
656 fftw_complex* fftOutput = new fftw_complex [ m_nFilterPoints ];
657 fftw_one (m_complexPlanForward, m_adComplexFftInput, fftOutput);
658 for (i = 0; i < m_nFilterPoints; i++) {
659 m_adComplexFftSignal[i].re = m_adFilter[i] * fftOutput[i].re;
660 m_adComplexFftSignal[i].im = m_adFilter[i] * fftOutput[i].im;
663 fftw_complex* ifftOutput = new fftw_complex [ m_nOutputPoints ];
664 fftw_one (m_complexPlanBackward, m_adComplexFftSignal, ifftOutput);
665 for (i = 0; i < m_nSignalPoints * m_iPreinterpolationFactor; i++)
666 output[i] = ifftOutput[i].re;
667 delete [] ifftOutput;
675 * convolve Discrete convolution of two functions
678 * r = convolve (f1, f2, dx, n, np, func_type)
679 * double r Convolved result
680 * double f1[], f2[] Functions to be convolved
681 * double dx Difference between successive x values
682 * int n Array index to center convolution about
683 * int np Number of points in f1 array
684 * int func_type EVEN or ODD or EVEN_AND_ODD function f2
687 * f1 is the projection data, its indices range from 0 to np - 1.
688 * The index for f2, the filter, ranges from -(np-1) to (np-1).
689 * There are 3 ways to handle the negative vertices of f2:
690 * 1. If we know f2 is an EVEN function, then f2[-n] = f2[n].
691 * All filters used in reconstruction are even.
692 * 2. If we know f2 is an ODD function, then f2[-n] = -f2[n]
693 * 3. If f2 is both ODD AND EVEN, then we must store the value of f2
694 * for negative indices. Since f2 must range from -(np-1) to (np-1),
695 * if we add (np - 1) to f2's array index, then f2's index will
696 * range from 0 to 2 * (np - 1), and the origin, x = 0, will be
697 * stored at f2[np-1].
701 ProcessSignal::convolve (const double func[], const double dx, const int n, const int np) const
705 #if UNOPTIMIZED_CONVOLUTION
706 for (int i = 0; i < np; i++)
707 sum += func[i] * m_adFilter[n - i + (np - 1)];
709 double* f2 = m_adFilter + n + (np - 1);
710 for (int i = 0; i < np; i++)
711 sum += *func++ * *f2--;
719 ProcessSignal::convolve (const float func[], const double dx, const int n, const int np) const
723 #if UNOPTIMIZED_CONVOLUTION
724 for (int i = 0; i < np; i++)
725 sum += func[i] * m_adFilter[n - i + (np - 1)];
727 double* f2 = m_adFilter + n + (np - 1);
728 for (int i = 0; i < np; i++)
729 sum += *func++ * *f2--;
737 ProcessSignal::finiteFourierTransform (const double input[], double output[], const int n, int direction)
739 std::complex<double>* complexOutput = new std::complex<double> [n];
741 finiteFourierTransform (input, complexOutput, n, direction);
742 for (int i = 0; i < n; i++)
743 output[i] = complexOutput[i].real();
744 delete [] complexOutput;
748 ProcessSignal::finiteFourierTransform (const double input[], std::complex<double> output[], const int n, int direction)
755 double angleIncrement = direction * 2 * PI / n;
756 for (int i = 0; i < n; i++) {
759 for (int j = 0; j < n; j++) {
760 double angle = i * j * angleIncrement;
761 sumReal += input[j] * cos(angle);
762 sumImag += input[j] * sin(angle);
768 output[i] = std::complex<double> (sumReal, sumImag);
774 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], std::complex<double> output[], const int n, int direction)
781 double angleIncrement = direction * 2 * PI / n;
782 for (int i = 0; i < n; i++) {
783 std::complex<double> sum (0,0);
784 for (int j = 0; j < n; j++) {
785 double angle = i * j * angleIncrement;
786 std::complex<double> exponentTerm (cos(angle), sin(angle));
787 sum += input[j] * exponentTerm;
797 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], double output[], const int n, int direction)
804 double angleIncrement = direction * 2 * PI / n;
805 for (int i = 0; i < n; i++) {
807 for (int j = 0; j < n; j++) {
808 double angle = i * j * angleIncrement;
809 sumReal += input[j].real() * cos(angle) - input[j].imag() * sin(angle);
818 // Table-based routines
821 ProcessSignal::finiteFourierTransform (const double input[], std::complex<double> output[], int direction) const
828 for (int i = 0; i < m_nFilterPoints; i++) {
829 double sumReal = 0, sumImag = 0;
830 for (int j = 0; j < m_nFilterPoints; j++) {
831 int tableIndex = i * j;
833 sumReal += input[j] * m_adFourierCosTable[tableIndex];
834 sumImag += input[j] * m_adFourierSinTable[tableIndex];
836 sumReal += input[j] * m_adFourierCosTable[tableIndex];
837 sumImag -= input[j] * m_adFourierSinTable[tableIndex];
841 sumReal /= m_nFilterPoints;
842 sumImag /= m_nFilterPoints;
844 output[i] = std::complex<double> (sumReal, sumImag);
848 // (a+bi) * (c + di) = (ac - bd) + (ad + bc)i
850 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], std::complex<double> output[], int direction) const
857 for (int i = 0; i < m_nFilterPoints; i++) {
858 double sumReal = 0, sumImag = 0;
859 for (int j = 0; j < m_nFilterPoints; j++) {
860 int tableIndex = i * j;
862 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
863 - input[j].imag() * m_adFourierSinTable[tableIndex];
864 sumImag += input[j].real() * m_adFourierSinTable[tableIndex]
865 + input[j].imag() * m_adFourierCosTable[tableIndex];
867 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
868 - input[j].imag() * -m_adFourierSinTable[tableIndex];
869 sumImag += input[j].real() * -m_adFourierSinTable[tableIndex]
870 + input[j].imag() * m_adFourierCosTable[tableIndex];
874 sumReal /= m_nFilterPoints;
875 sumImag /= m_nFilterPoints;
877 output[i] = std::complex<double> (sumReal, sumImag);
882 ProcessSignal::finiteFourierTransform (const std::complex<double> input[], double output[], int direction) const
889 for (int i = 0; i < m_nFilterPoints; i++) {
891 for (int j = 0; j < m_nFilterPoints; j++) {
892 int tableIndex = i * j;
894 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
895 - input[j].imag() * m_adFourierSinTable[tableIndex];
897 sumReal += input[j].real() * m_adFourierCosTable[tableIndex]
898 - input[j].imag() * -m_adFourierSinTable[tableIndex];
902 sumReal /= m_nFilterPoints;