Changeset 11703 for trunk/psLib/src/fft
- Timestamp:
- Feb 7, 2007, 6:17:58 PM (19 years ago)
- Location:
- trunk/psLib/src/fft
- Files:
-
- 4 edited
-
psImageFFT.c (modified) (2 diffs)
-
psImageFFT.h (modified) (2 diffs)
-
psVectorFFT.c (modified) (3 diffs)
-
psVectorFFT.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/fft/psImageFFT.c
r11668 r11703 1 /** @file psImageFFT.c 2 * 3 * @brief Contains FFT transform related functions for psImage. 4 * 5 * @author Robert DeSonia, MHPCC 6 * 7 * @version $Revision: 1.20 $ $Name: not supported by cvs2svn $ 8 * @date $Date: 2007-02-06 21:36:09 $ 9 * 10 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 11 */ 1 /// @file psImageFFT.c 2 /// 3 /// @brief Contains FFT transform related functions for psImage. 4 /// 5 /// @author Paul Price, IfA 6 /// @author Robert DeSonia, MHPCC 7 /// 8 /// @version $Revision: 1.21 $ $Name: not supported by cvs2svn $ 9 /// @date $Date: 2007-02-08 04:17:58 $ 10 /// 11 /// Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 12 /// 12 13 13 14 #ifdef HAVE_CONFIG_H … … 20 21 #include <fftw3.h> 21 22 22 #include "ps ImageFFT.h"23 #include "psAssert.h" 23 24 #include "psError.h" 24 25 #include "psMemory.h" 25 26 #include "psLogMsg.h" 27 #include "psConstants.h" 26 28 #include "psImageStructManip.h" 27 28 29 30 #define PS_FFTW_PLAN_RIGOR FFTW_ESTIMATE 31 32 static bool p_fftwWisdomImported = false; 33 34 psImage* psImageFFT(psImage* out, const psImage* image, psFFTFlags direction) 35 { 36 psU32 numCols; 37 psU32 numRows; 38 psElemType type; 39 fftwf_plan plan; 40 41 /* got good image data? */ 42 if (image == NULL) { 43 psFree(out); 29 #include "psImageFFT.h" 30 31 32 #define FFTW_PLAN_RIGOR FFTW_ESTIMATE // How rigorous the FFTW planning is 33 34 static psBool fftwWisdomImported = false; // Has the FFTW wisdom been imported yet? 35 36 bool psImageForwardFFT(psImage **real, psImage **imag, const psImage *in) 37 { 38 PS_ASSERT_IMAGE_NON_NULL(in, false); 39 PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, false); 40 PS_ASSERT_PTR_NON_NULL(real, false); 41 PS_ASSERT_PTR_NON_NULL(imag, false); 42 43 // Make sure the system-level wisdom information is imported. 44 if (!fftwWisdomImported) { 45 fftwf_import_system_wisdom(); 46 fftwWisdomImported = true; 47 } 48 49 int numCols = in->numCols; // Number of columns 50 int numRows = in->numRows; // Number of rows 51 52 psF32 *input; // Input data, for FFTW 53 if (!in->parent) { 54 // No parent --- can just use the data buffer 55 input = psMemIncrRefCounter(in->p_rawDataBuffer); 56 } else { 57 // Need to copy the data 58 input = psAlloc(numCols * numRows); 59 for (int y = 0; y < numRows; y++) { 60 memcpy(&input[y * numRows], in->data.F32[y], numCols); 61 } 62 } 63 64 // Do the FFT 65 fftwf_complex *out = fftwf_malloc((numCols/2 + 1) * numRows * sizeof(fftwf_complex)); // Output data 66 fftwf_plan plan = fftwf_plan_dft_r2c_2d(numRows, numCols, input, out, FFTW_PLAN_RIGOR); 67 fftwf_execute(plan); 68 fftwf_destroy_plan(plan); 69 psFree(input); 70 71 // Pull the real and imaginary parts out 72 numCols = numCols/2 + 1; // x dimension is halved by FFTW 73 *real = psImageRecycle(*real, numCols, numRows, PS_TYPE_F32); 74 *imag = psImageRecycle(*imag, numCols, numRows, PS_TYPE_F32); 75 for (int y = 0, index = 0; y < numRows; y++) { 76 for (int x = 0; x < numCols; index++, x++) { 77 #if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 78 // C99 complex support 79 (*real)->data.F32[y][x] = creal(out[index]); 80 (*imag)->data.F32[y][x] = cimag(out[index]); 81 #else 82 // FFTW's backup complex support 83 (*real)->data.F32[y][x] = out[index][0]; 84 (*imag)->data.F32[y][x] = out[index][1]; 85 #endif 86 } 87 } 88 fftwf_free(out); 89 90 return true; 91 } 92 93 bool psImageBackwardFFT(psImage **out, const psImage *real, const psImage *imag, int origCols) 94 { 95 PS_ASSERT_IMAGE_NON_NULL(real, false); 96 PS_ASSERT_IMAGE_TYPE(real, PS_TYPE_F32, false); 97 PS_ASSERT_IMAGE_NON_NULL(imag, false); 98 PS_ASSERT_IMAGE_TYPE(imag, PS_TYPE_F32, false); 99 PS_ASSERT_IMAGES_SIZE_EQUAL(real, imag, false); 100 PS_ASSERT_PTR_NON_NULL(out, false); 101 102 int numCols = real->numCols; // Number of columns 103 int numRows = real->numRows; // Number of rows 104 105 // Because of the way FFT r2c and c2r work, need the number of columns in the target to be: 106 // 2 * numCols = 2*(numCols/2 + 1) = origCols % 2 ? origCols + 1 : origCols + 2 107 if (2 * numCols != ((origCols % 2) ? origCols + 1 : origCols + 2)) { 108 psError(PS_ERR_BAD_PARAMETER_VALUE, false, 109 "Number of columns in FFT-ed images (%d) should be origCols (%d) / 2 + 1 = %d", 110 numCols, origCols, origCols/2 + 1); 111 return false; 112 } 113 114 if (*out && (*out)->parent) { 115 // It has a parent, so we can't write directly into the buffer. 116 // It had better be the correct size and type, because we don't want to resize a child image 117 PS_ASSERT_IMAGE_SIZE(*out, origCols, numRows, false); 118 PS_ASSERT_IMAGE_TYPE(*out, PS_TYPE_F32, false); 119 } 120 121 122 // Make sure the system-level wisdom information is imported. 123 if (!fftwWisdomImported) { 124 fftwf_import_system_wisdom(); 125 fftwWisdomImported = true; 126 } 127 128 // Stuff the real and imaginary parts in 129 psF32 *target = psAlloc(2 * numCols * numRows * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Target for FFTW 130 fftwf_complex *in = fftwf_malloc(numCols * numRows * sizeof(fftwf_complex)); // Input data 131 for (int y = 0, index = 0; y < numRows; y++) { 132 for (int x = 0; x < numCols; index++, x++) { 133 #if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 134 // C99 complex support 135 in[index] = real->data.F32[y][x] + imag->data.F32[y][x] * I; 136 #else 137 // FFTW's backup complex support 138 in[index][0] = real->data.F32[y][x]; 139 in[index][1] = imag->data.F32[y][x]; 140 #endif 141 } 142 } 143 144 // Do the FFT 145 fftwf_plan plan = fftwf_plan_dft_c2r_2d(numRows, origCols, in, target, FFTW_PLAN_RIGOR); 146 fftwf_execute(plan); 147 fftwf_destroy_plan(plan); 148 fftwf_free(in); 149 150 if (!(*out) || !(*out)->parent) { 151 *out = psImageRecycle(*out, origCols, numRows, PS_TYPE_F32); 152 } 153 154 // Copy the target pixels into the output 155 // There's a slight offset --- target has the additional padding required by FFTW, 156 // while the output doesn't. 157 for (int y = 0, index = 0; y < numRows; y++, index += origCols) { 158 memcpy(&(*out)->data.F32[y][0], &target[index], numRows * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); 159 } 160 psFree(target); 161 162 return true; 163 } 164 165 psImage* psImagePowerSpectrum(psImage *out, const psImage *in) 166 { 167 PS_ASSERT_IMAGE_NON_NULL(in, NULL); 168 PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL); 169 170 psImage *real = NULL; // Real component of FFT 171 psImage *imag = NULL; // Imaginary component of FFT 172 173 if (!psImageForwardFFT(&real, &imag, in)) { 174 psError(PS_ERR_UNKNOWN, false, "Unable to perform forward FFT."); 44 175 return NULL; 45 176 } 46 177 47 if ( ((direction & PS_FFT_FORWARD) != 0) ) { 48 if ((direction & PS_FFT_REVERSE) != 0) { 49 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 50 _("Can not specify both PS_FFT_FORWARD and PS_FFT_REVERSE options.")); 51 psFree(out); 52 return NULL; 53 } 54 if ((direction & PS_FFT_REAL_RESULT) != 0) { 55 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 56 _("The PS_FFT_FORWARD and PS_FFT_REAL_RESULT combinition is not supported.")); 57 psFree(out); 58 return NULL; 59 } 60 } else if ((direction & PS_FFT_REVERSE) == 0) { 178 int numCols = real->numCols; // Number of columns 179 int numRows = real->numRows; // Number of rows 180 181 float norm = 1.0 / PS_SQR(in->numCols) / PS_SQR(in->numRows); 182 for (int y = 0; y < numRows; y++) { 183 for (int x = 0; x < numCols; x++) { 184 // Power spectrum is the square of the complex modulus 185 real->data.F32[y][x] = norm * (PS_SQR(real->data.F32[y][x]) + PS_SQR(imag->data.F32[y][x])); 186 } 187 } 188 psFree(imag); 189 190 return real; 191 } 192 193 194 195 bool psImageComplexMultiply(psImage **outReal, psImage **outImag, 196 const psImage *in1Real, const psImage *in1Imag, 197 const psImage *in2Real, const psImage *in2Imag) 198 { 199 PS_ASSERT_IMAGE_NON_NULL(in1Real, false); 200 PS_ASSERT_IMAGE_NON_NULL(in1Imag, false); 201 PS_ASSERT_IMAGE_NON_NULL(in2Real, false); 202 PS_ASSERT_IMAGE_NON_NULL(in2Imag, false); 203 PS_ASSERT_IMAGE_TYPE(in1Real, PS_TYPE_F32, false); 204 PS_ASSERT_IMAGE_TYPE(in1Imag, PS_TYPE_F32, false); 205 PS_ASSERT_IMAGE_TYPE(in2Real, PS_TYPE_F32, false); 206 PS_ASSERT_IMAGE_TYPE(in2Imag, PS_TYPE_F32, false); 207 PS_ASSERT_IMAGES_SIZE_EQUAL(in1Imag, in1Real, false); 208 PS_ASSERT_IMAGES_SIZE_EQUAL(in2Real, in1Real, false); 209 PS_ASSERT_IMAGES_SIZE_EQUAL(in2Imag, in1Real, false); 210 PS_ASSERT_PTR_NON_NULL(outReal, false); 211 PS_ASSERT_PTR_NON_NULL(outImag, false); 212 if (*outReal) { 213 PS_ASSERT_IMAGE_NON_NULL(*outReal, false); 214 PS_ASSERT_IMAGE_NON_NULL(*outImag, false); 215 } else if (*outImag) { 61 216 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 62 _("Must specify either PS_FFT_FORWARD or PS_FFT_REVERSE option.")); 63 psFree(out); 64 return NULL; 65 } 66 67 type = image->type.type; 68 69 /* make sure the system-level wisdom information is imported. */ 70 if (!p_fftwWisdomImported) { 71 fftwf_import_system_wisdom(); 72 p_fftwWisdomImported = true; 73 } 74 75 numRows = image->numRows; 76 numCols = image->numCols; 77 78 // n.b. FFTW can perform a in-place transform at the same rate or faster than out-of-place. 79 psS32 sign = ((direction & PS_FFT_FORWARD) != 0) ? FFTW_FORWARD : FFTW_BACKWARD; 80 81 fftwf_complex* outBuffer = fftwf_malloc(numRows*numCols*sizeof(fftwf_complex)); 82 p_psImageCopyToRawBuffer(outBuffer, image, PS_TYPE_C32); 83 84 plan = fftwf_plan_dft_2d(numRows, numCols, 85 outBuffer, 86 outBuffer, 87 sign, 88 PS_FFTW_PLAN_RIGOR); 89 90 /* check if a plan exists now -- if not, it is a real problem at this point */ 91 if (plan == NULL) { 92 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 93 _("Could not create a valid FFT plan to perform the transform.")); 94 psFree(out); 95 return NULL; 96 } 97 98 /* finally, call FFTW with the plan made above */ 99 fftwf_execute(plan); 100 101 fftwf_destroy_plan(plan); 102 103 if (direction & PS_FFT_REAL_RESULT) { 104 // n.b., we do this instead of using fftwf_plan_dft_c2r because that 105 // plan requires a half-image, which would require a image reordering 106 // that is not as simple as performing a normal complex transform and 107 // then taking the real part of the result. If performance here 108 // becomes an issue, the use of fftwf_plan_dft_r2c should be considered 109 // as well as fftwf_plan_dft_c2r. 110 out = psImageRecycle(out,numCols,numRows,PS_TYPE_F32); 111 int index = 0; 112 for (int row=0; row < numRows; row++) { 113 psF32* outRow = out->data.F32[row]; 114 for (int col=0; col < numCols; col++) { 115 outRow[col] = crealf(outBuffer[index++]); // take just the real part 116 } 117 } 217 "If the output real part is provided, the output imaginary part must also be provided."); 218 return false; 219 } 220 221 int numRows = in1Real->numRows; // Number of rows 222 int numCols = in1Real->numCols; // Number of columns 223 224 // Need to worry if the outputs are children 225 psImage *targetReal, *targetImag; // Target real and imaginary parts 226 227 if ((*outReal)->parent) { 228 // It had better be the correct size and type, because we don't want to resize a child image 229 PS_ASSERT_IMAGE_TYPE(*outReal, PS_TYPE_F32, false); 230 PS_ASSERT_IMAGE_SIZE(*outReal, numCols, numRows, false); 231 targetReal = psImageAlloc(numCols, numRows, PS_TYPE_F32); 118 232 } else { 119 out = psImageRecycle(out,numCols,numRows,PS_TYPE_C32); 120 int index = 0; 121 for (int row=0; row < numRows; row++) { 122 psC32* outRow = out->data.C32[row]; 123 for (int col=0; col < numCols; col++) { 124 outRow[col] = outBuffer[index++]; // take just the real part 125 } 126 } 127 // memcpy(out->rawDataBuffer, outBuffer, numRows*numCols*sizeof(fftwf_complex)); 128 } 129 130 fftwf_free(outBuffer); 131 132 return out; 133 134 } 135 136 psImage* psImageReal(psImage* out, const psImage* in) 137 { 138 psElemType type; 139 psU32 numCols; 140 psU32 numRows; 141 142 if (in == NULL) { 143 psFree(out); 144 return NULL; 145 } 146 147 type = in->type.type; 148 numCols = in->numCols; 149 numRows = in->numRows; 150 151 /* if not a complex number, this is logically just a copy then */ 152 if (!PS_IS_PSELEMTYPE_COMPLEX(type)) { 153 return psImageCopy(out, in, type); 154 } 155 156 if (type == PS_TYPE_C32) { 157 psF32* outRow; 158 psC32* inRow; 159 160 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F32); 161 for (psU32 row = 0; row < numRows; row++) { 162 outRow = out->data.F32[row]; 163 inRow = in->data.C32[row]; 164 165 for (psU32 col = 0; col < numCols; col++) { 166 outRow[col] = crealf(inRow[col]); 167 } 168 } 169 } else if (type == PS_TYPE_C64) { 170 psF64* outRow; 171 psC64* inRow; 172 173 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F64); 174 for (psU32 row = 0; row < numRows; row++) { 175 outRow = out->data.F64[row]; 176 inRow = in->data.C64[row]; 177 178 for (psU32 col = 0; col < numCols; col++) { 179 outRow[col] = creal(inRow[col]); 180 } 181 } 233 *outReal = psImageRecycle(*outReal, numCols, numRows, PS_TYPE_F32); 234 targetReal = psMemIncrRefCounter(*outReal); 235 } 236 if ((*outImag)->parent) { 237 // It had better be the correct size and type, because we don't want to resize a child image 238 if ((*outReal)->numCols != numCols || (*outReal)->numRows != numRows || 239 (*outImag)->type.type != PS_TYPE_F32) { 240 // Plug potential memory leak --- need to free targetReal if there's a problem 241 psFree(targetReal); 242 } 243 PS_ASSERT_IMAGE_TYPE(*outReal, PS_TYPE_F32, false); 244 PS_ASSERT_IMAGE_SIZE(*outReal, numCols, numRows, false); 245 targetImag = psImageAlloc(numCols, numRows, PS_TYPE_F32); 182 246 } else { 183 char* typeStr; 184 PS_TYPE_NAME(typeStr,type); 185 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 186 _("Specified psImage type, %s, is not supported."), 187 typeStr); 188 189 psFree(out); 190 return NULL; 191 } 192 193 return out; 194 } 195 196 psImage* psImageImaginary(psImage* out, const psImage* in) 197 { 198 psElemType type; 199 psU32 numCols; 200 psU32 numRows; 201 202 if (in == NULL) { 203 psFree(out); 204 return NULL; 205 } 206 207 type = in->type.type; 208 numCols = in->numCols; 209 numRows = in->numRows; 210 211 /* if not a complex image type, this is logically just zeroed image of same size */ 212 if (!PS_IS_PSELEMTYPE_COMPLEX(type)) { 213 out = psImageRecycle(out, numCols, numRows, type); 214 memset(out->data.V[0], 0, PSELEMTYPE_SIZEOF(type) * numCols * numRows); 215 return out; 216 } 217 218 if (type == PS_TYPE_C32) { 219 psF32* outRow; 220 psC32* inRow; 221 222 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F32); 223 for (psU32 row = 0; row < numRows; row++) { 224 outRow = out->data.F32[row]; 225 inRow = in->data.C32[row]; 226 227 for (psU32 col = 0; col < numCols; col++) { 228 outRow[col] = cimagf(inRow[col]); 229 } 230 } 231 } else if (type == PS_TYPE_C64) { 232 psF64* outRow; 233 psC64* inRow; 234 235 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F64); 236 for (psU32 row = 0; row < numRows; row++) { 237 outRow = out->data.F64[row]; 238 inRow = in->data.C64[row]; 239 240 for (psU32 col = 0; col < numCols; col++) { 241 outRow[col] = cimag(inRow[col]); 242 } 243 } 244 } else { 245 char* typeStr; 246 PS_TYPE_NAME(typeStr,type); 247 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 248 _("Specified psImage type, %s, is not supported."), 249 typeStr); 250 psFree(out); 251 return NULL; 252 } 253 254 return out; 255 } 256 257 psImage* psImageComplex(psImage* out, const psImage* real, const psImage* imag) 258 { 259 psElemType type; 260 psU32 numCols; 261 psU32 numRows; 262 263 if (real == NULL || imag == NULL) { 264 psFree(out); 265 return NULL; 266 } 267 268 type = real->type.type; 269 numCols = real->numCols; 270 numRows = real->numRows; 271 272 if (imag->type.type != type) { 273 char* typeStrReal; 274 char* typeStrImag; 275 PS_TYPE_NAME(typeStrReal,type); 276 PS_TYPE_NAME(typeStrImag,imag->type.type); 277 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 278 _("Real psImage type (%s) and imaginary psImage type (%s) must be the same."), 279 typeStrReal,typeStrImag); 280 psFree(out); 281 return NULL; 282 } 283 284 if (imag->numCols != numCols || imag->numRows != numRows) { 285 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 286 _("Real psImage size (%dx%d) and imaginary psImage size (%dx%d) must be the same."), 287 numCols, numRows, imag->numCols, imag->numRows); 288 psFree(out); 289 return NULL; 290 } 291 292 if (type == PS_TYPE_F32) { 293 psC32* outRow; 294 psF32* realRow; 295 psF32* imagRow; 296 297 out = psImageRecycle(out, numCols, numRows, PS_TYPE_C32); 298 299 for (psU32 row = 0; row < numRows; row++) { 300 outRow = out->data.C32[row]; 301 realRow = real->data.F32[row]; 302 imagRow = imag->data.F32[row]; 303 304 for (psU32 col = 0; col < numCols; col++) { 305 outRow[col] = realRow[col] + I * imagRow[col]; 306 } 307 } 308 } else if (type == PS_TYPE_F64) { 309 psC64* outRow; 310 psF64* realRow; 311 psF64* imagRow; 312 313 out = psImageRecycle(out, numCols, numRows, PS_TYPE_C64); 314 for (psU32 row = 0; row < numRows; row++) { 315 outRow = out->data.C64[row]; 316 realRow = real->data.F64[row]; 317 imagRow = imag->data.F64[row]; 318 319 for (psU32 col = 0; col < numCols; col++) { 320 outRow[col] = realRow[col] + I * imagRow[col]; 321 } 322 } 323 } else { 324 char* typeStr; 325 PS_TYPE_NAME(typeStr,type); 326 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 327 _("Input psImage type, %s, is required to be either psF32 or psF64."), 328 typeStr); 329 psFree(out); 330 return NULL; 331 } 332 333 334 return out; 335 } 336 337 psImage* psImageConjugate(psImage* out, const psImage* in) 338 { 339 psElemType type; 340 psU32 numCols; 341 psU32 numRows; 342 343 if (in == NULL) { 344 psFree(out); 345 return NULL; 346 } 347 348 type = in->type.type; 349 numCols = in->numCols; 350 numRows = in->numRows; 351 352 /* if not a complex image, this is logically just a image copy */ 353 if (!PS_IS_PSELEMTYPE_COMPLEX(type)) { 354 return psImageCopy(out, in, type); 355 } 356 357 if (type == PS_TYPE_C32) { 358 psC32* outRow; 359 psC32* inRow; 360 361 out = psImageRecycle(out, numCols, numRows, PS_TYPE_C32); 362 for (psU32 row = 0; row < numRows; row++) { 363 outRow = out->data.C32[row]; 364 inRow = in->data.C32[row]; 365 366 for (psU32 col = 0; col < numCols; col++) { 367 outRow[col] = crealf(inRow[col]) - I * cimagf(inRow[col]); 368 } 369 } 370 } else if (type == PS_TYPE_C64) { 371 psC64* outRow; 372 psC64* inRow; 373 374 out = psImageRecycle(out, numCols, numRows, PS_TYPE_C64); 375 for (psU32 row = 0; row < numRows; row++) { 376 outRow = out->data.C64[row]; 377 inRow = in->data.C64[row]; 378 379 for (psU32 col = 0; col < numCols; col++) { 380 outRow[col] = creal(inRow[col]) - I * cimag(inRow[col]); 381 } 382 } 383 } else { 384 char* typeStr; 385 PS_TYPE_NAME(typeStr,type); 386 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 387 _("Input psImage type, %s, is required to be either psC32 or psC64."), 388 typeStr); 389 psFree(out); 390 return NULL; 391 } 392 393 return out; 394 } 395 396 psImage* psImagePowerSpectrum(psImage* out, const psImage* in) 397 { 398 psElemType type; 399 psU32 numCols; 400 psU32 numRows; 401 402 if (in == NULL) { 403 psFree(out); 404 return NULL; 405 } 406 407 type = in->type.type; 408 numCols = in->numCols; 409 numRows = in->numRows; 410 411 if (type == PS_TYPE_C32) { 412 psF32* outRow; 413 psC32* inRow; 414 psF32 real; 415 psF32 imag; 416 psF32 fNumCols = numCols; 417 psF32 fNumRows = numRows; 418 psF32 numElementsSquared = fNumCols * fNumCols * fNumRows * fNumRows; 419 420 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F32); 421 for (psU32 row = 0; row < numRows; row++) { 422 outRow = out->data.F32[row]; 423 inRow = in->data.C32[row]; 424 425 for (psU32 col = 0; col < numCols; col++) { 426 real = crealf(inRow[col]); 427 imag = cimagf(inRow[col]); 428 outRow[col] = (real * real + imag * imag) / numElementsSquared; 429 } 430 } 431 } else if (type == PS_TYPE_C64) { 432 psF64* outRow; 433 psC64* inRow; 434 psF64 real; 435 psF64 imag; 436 psF64 numElementsSquared = numCols * numCols * numRows * numRows; 437 438 out = psImageRecycle(out, numCols, numRows, PS_TYPE_F64); 439 for (psU32 row = 0; row < numRows; row++) { 440 outRow = out->data.F64[row]; 441 inRow = in->data.C64[row]; 442 443 for (psU32 col = 0; col < numCols; col++) { 444 real = creal(inRow[col]); 445 imag = cimag(inRow[col]); 446 outRow[col] = (real * real + imag * imag) / numElementsSquared; 447 } 448 } 449 } else { 450 char* typeStr; 451 PS_TYPE_NAME(typeStr,type); 452 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 453 _("Input psImage type, %s, is required to be either psC32 or psC64."), 454 typeStr); 455 psFree(out); 456 return NULL; 457 } 458 459 return out; 460 461 } 247 *outImag = psImageRecycle(*outImag, numCols, numRows, PS_TYPE_F32); 248 targetImag = psMemIncrRefCounter(*outImag); 249 } 250 251 for (int y = 0; y < numRows; y++) { 252 for (int x = 0; x < numCols; x++) { 253 // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i 254 float real = in1Real->data.F32[y][x] * in2Real->data.F32[y][x] - 255 in1Imag->data.F32[y][x] * in2Imag->data.F32[y][x]; 256 float imag = in1Imag->data.F32[y][x] * in2Real->data.F32[y][x] + 257 in1Real->data.F32[y][x] * in2Imag->data.F32[y][x]; 258 targetReal->data.F32[y][x] = real; 259 targetImag->data.F32[y][x] = imag; 260 } 261 } 262 263 if ((*outReal)->parent) { 264 *outReal = psImageCopy(*outReal, targetReal, PS_TYPE_F32); 265 } 266 if ((*outImag)->parent) { 267 *outImag = psImageCopy(*outImag, targetImag, PS_TYPE_F32); 268 } 269 270 psFree(targetReal); 271 psFree(targetImag); 272 273 return true; 274 } -
trunk/psLib/src/fft/psImageFFT.h
r11248 r11703 1 /* @file psImageFFT.h 2 * @brief Contains FFT transform related functions for psImage 3 * 4 * @author Robert DeSonia, MHPCC 5 * 6 * @version $Revision: 1.7 $ $Name: not supported by cvs2svn $ 7 * @date $Date: 2007-01-23 22:47:22 $ 8 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 9 */ 1 /// @file psImageFFT.h 2 /// @brief Contains FFT transform related functions for psImage 3 /// 4 /// @author Paul Price, IfA 5 /// @author Robert DeSonia, MHPCC 6 /// 7 /// @version $Revision: 1.8 $ $Name: not supported by cvs2svn $ 8 /// @date $Date: 2007-02-08 04:17:58 $ 9 /// Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 10 /// 10 11 11 12 #ifndef PS_IMAGE_FFT_H … … 13 14 14 15 #include "psImage.h" 15 #include "psVectorFFT.h" // for psFFTFlags16 16 17 17 /// @addtogroup MathOps Mathematical Operations 18 18 /// @{ 19 19 20 /** Forward and reverse FFT calculations. 21 * 22 * This takes as input the image of interest (in) and the direction 23 * (direction), which is specified by an enumerated type psFftDirection. 24 * The input image may be of type psF32 or psC32, the result is always 25 * psC32. If the input vector is psF32, the direction must be forward. 26 * 27 * @return psImage* the FFT transformation result 28 */ 29 psImage* psImageFFT( 30 psImage* out, ///< a psImage to recycle. If NULL, a new psImage is made. 31 const psImage* image, ///< the psImage to apply transform to 32 psFFTFlags direction ///< the direction of the transform 33 ); 20 /// Forward FFT of an image 21 /// 22 /// Applies a forward FFT (exponent -1), with the result returned in both real and imaginary parts. The FFT 23 /// is not normalised (a forward followed by a reverse is the original scaled by the total number of pixels). 24 /// The FFT takes advantage of the fact that the input is purely real; hence the output number of columns is 25 /// numCols/2 + 1 (with division rounding down). Only implemented for F32 input. 26 bool psImageForwardFFT(psImage **real, ///< Real part of FFT 27 psImage **imag, ///< Imaginary part of FFT 28 const psImage *in///< Input image (F32) 29 ); 34 30 35 /** extract the real portion of a complex image 36 * 37 * @return psImage* real portion of the input image. 38 */ 39 psImage* psImageReal( 40 psImage* out, ///< a psImage to recycle. If NULL, a new psImage is made. 41 const psImage* in ///< the psImage to extract real portion from 42 ); 31 /// Backward FFT of an image 32 /// 33 /// Applies a backward FFT (exponent +1) from the real and imaginary parts with the (purely) real result 34 /// returned. The FFT is not normalised (a forward followed by a reverse is the original scaled by the total 35 /// number of pixels). The FFT takes advantage of the fact that the output will be purely real; hence the 36 /// input number of columns is numCols/2 + 1 (with division rounding down); to manage the redundancy (is the 37 /// original number of columns even or odd?), we need the original number of columns (the number of columns of 38 /// the image that was input to psImageForwardFFT) to be provided. Only implemented for F32 input. 39 bool psImageBackwardFFT(psImage **out,///< Output image 40 const psImage *real, ///< Real input (F32) 41 const psImage *imag, ///< Imaginary input (F32) 42 int origCols ///< Original number of columns 43 ); 43 44 44 /** extract the imaginary portion of a complex image45 *46 * @return psImage* imaginary portion of the input image.47 */48 psImage* psImageImaginary(49 psImage* out, ///< a psImage to recycle. If NULL, a new psImage is made.50 const psImage* in ///< the psImage to extract imaginary portion from51 );52 45 53 /** creates a complex image from separate real and imaginary plane images 54 * 55 * @return psImage* resulting complex image 56 */ 57 psImage* psImageComplex( 58 psImage* out, ///< a psImage to recycle. If NULL, a new psImage is made. 59 const psImage* real, ///< the real plane image 60 const psImage* imag ///< the imaginary plane image 61 ); 46 /// Power spectrum of an image 47 /// 48 /// Generates the power spectrum of an image. Only implemented for F32 input. 49 psImage* psImagePowerSpectrum(psImage *out, const psImage *in); 62 50 63 /** computes the complex conjugate of an image 64 * 65 * @return psImage* the complex conjugate of the 'in' image 66 */ 67 psImage* psImageConjugate( 68 psImage* out, ///< a psImage to recycle. If NULL, a new psImage is made. 69 const psImage* in ///< the psImage to compute conjugate of 70 ); 71 72 /** computes the power spectrum of an image 73 * 74 * @return psImage* the power spectrum of the 'in' image 75 */ 76 psImage* psImagePowerSpectrum( 77 psImage* out, ///< a psImage to recycle. If NULL, a new psImage is made. 78 const psImage* in ///< the psImage to power spectrum of 79 ); 51 /// Multiply complex images 52 /// 53 /// The input images are the real and imaginary parts of each of two images. The real and imaginary parts 54 /// of the output image are returned. Only implemented for F32 input. 55 bool psImageComplexMultiply(psImage **outReal, ///< Real part of output 56 psimage **outImag, ///< Imaginary part of output 57 const psImage *in1Real, ///< Real part of input 1 58 const psImage *in1Imag, ///< Imaginary part of input 1 59 const psImage *in2Real, ///< Real part of input 2 60 const psImage *in2Imag ///< Imaginary part of input 2 61 ); 80 62 81 63 /// @} -
trunk/psLib/src/fft/psVectorFFT.c
r11668 r11703 3 3 * @brief Contains FFT transform related functions for psVector 4 4 * 5 * @author Paul Price, IfA 5 6 * @author Robert DeSonia, MHPCC 6 7 * 7 * @version $Revision: 1.3 6$ $Name: not supported by cvs2svn $8 * @date $Date: 2007-02-0 6 21:36:09$8 * @version $Revision: 1.37 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2007-02-08 04:17:58 $ 9 10 * 10 11 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii … … 12 13 13 14 #ifdef HAVE_CONFIG_H 14 # include "config.h"15 #include "config.h" 15 16 #endif 16 17 … … 21 22 #include <fftw3.h> 22 23 23 #include "ps VectorFFT.h"24 #include "psAssert.h" 24 25 #include "psError.h" 25 26 #include "psMemory.h" 26 27 #include "psLogMsg.h" 28 #include "psConstants.h" 29 #include "psVectorFFT.h" 30 31 #define FFTW_PLAN_RIGOR FFTW_ESTIMATE // How rigorous the FFTW planning is 32 33 static psBool fftwWisdomImported = false; // Has the system wisdom been imported? 34 35 bool psVectorForwardFFT(psVector **real, psVector **imag, const psVector *in) 36 { 37 PS_ASSERT_VECTOR_NON_NULL(in, false); 38 PS_ASSERT_VECTOR_TYPE(in, PS_TYPE_F32, false); 39 PS_ASSERT_PTR_NON_NULL(real, false); 40 PS_ASSERT_PTR_NON_NULL(imag, false); 41 42 // Make sure the system-level wisdom information is imported. 43 if (!fftwWisdomImported) { 44 fftwf_import_system_wisdom(); 45 fftwWisdomImported = true; 46 } 47 48 long num = in->n; // Number of elements 49 50 // Do the FFT 51 fftwf_complex *out = fftwf_malloc(num * sizeof(fftwf_complex)); // Output data 52 fftwf_plan plan = fftwf_plan_dft_r2c_1d(num, in->data.F32, out, FFTW_PLAN_RIGOR); 53 fftwf_execute(plan); 54 fftwf_destroy_plan(plan); 55 56 // Pull the real and imaginary parts out 57 *real = psVectorRecycle(*real, num/2 + 1, PS_TYPE_F32); 58 *imag = psVectorRecycle(*imag, num/2 + 1, PS_TYPE_F32); 59 for (int i = 0; i < num; i++) { 60 #if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 61 // C99 complex support 62 (*real)->data.F32[i] = creal(out[i]); 63 (*imag)->data.F32[i] = cimag(out[i]); 64 #else 65 // FFTW's backup complex support 66 (*real)->data.F32[i] = out[i][0]; 67 (*imag)->data.F32[i] = out[i][1]; 68 #endif 69 } 70 fftwf_free(out); 71 72 return true; 73 } 74 75 bool psVectorBackwardFFT(psVector **out, const psVector *real, const psVector *imag) 76 { 77 PS_ASSERT_VECTOR_NON_NULL(real, false); 78 PS_ASSERT_VECTOR_TYPE(real, PS_TYPE_F32, false); 79 PS_ASSERT_VECTOR_NON_NULL(imag, false); 80 PS_ASSERT_VECTOR_TYPE(imag, PS_TYPE_F32, false); 81 PS_ASSERT_VECTORS_SIZE_EQUAL(real, imag, false); 82 PS_ASSERT_PTR_NON_NULL(out, false); 83 84 // Make sure the system-level wisdom information is imported. 85 if (!fftwWisdomImported) { 86 fftwf_import_system_wisdom(); 87 fftwWisdomImported = true; 88 } 89 90 long num = real->n; // Number of elements 91 92 // Stuff the real and imaginary parts in 93 fftwf_complex *in = fftwf_malloc(num * sizeof(fftwf_complex)); // Input data 94 for (int i = 0; i < num; i++) { 95 #if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) 96 // C99 complex support 97 in[i] = real->data.F32[i] + imag->data.F32[i] * I; 98 #else 99 // FFTW's backup complex support 100 in[i][0] = real->data.F32[i]; 101 in[i][1] = imag->data.F32[i]; 102 #endif 103 } 27 104 28 105 106 // Do the FFT 107 *out = psVectorRecycle(*out, 2 * num, PS_TYPE_F32); 108 fftwf_plan plan = fftwf_plan_dft_c2r_1d(2 * num, in, (*out)->data.F32, FFTW_PLAN_RIGOR); 109 fftwf_execute(plan); 110 fftwf_destroy_plan(plan); 29 111 30 #define P_FFTW_PLAN_RIGOR FFTW_ESTIMATE 112 fftwf_free(in); 31 113 32 static bool p_fftwWisdomImported = false; 114 return true; 115 } 33 116 34 psVector * psVectorFFT(psVector* out, const psVector* in, psFFTFlags direction)117 psVector *psVectorPowerSpectrum(psVector* out, const psVector* in) 35 118 { 36 psU32 numElements; 37 psElemType type; 38 fftwf_plan plan; 119 PS_ASSERT_VECTOR_NON_NULL(in, NULL); 120 PS_ASSERT_VECTOR_TYPE(in, PS_TYPE_F32, NULL); 39 121 40 /* got good image data? */ 41 if (in == NULL) { 42 psFree(out); 122 psVector *real = NULL; // Real component of FFT 123 psVector *imag = NULL; // Imaginary component of FFT 124 125 if (!psVectorForwardFFT(&real, &imag, in)) { 126 psError(PS_ERR_UNKNOWN, false, "Unable to perform forward FFT."); 43 127 return NULL; 44 128 } 45 129 46 type = in->type.type;130 int num = real->n; // Number of elements 47 131 48 /* make sure the system-level wisdom information is imported. */ 49 if (!p_fftwWisdomImported) { 50 fftwf_import_system_wisdom(); 51 p_fftwWisdomImported = true; 132 float norm = 1.0 / PS_SQR(in->n); 133 for (int i = 0; i < num; i++) { 134 // Power spectrum is the square of the complex modulus 135 real->data.F32[i] = norm * (PS_SQR(real->data.F32[i]) + PS_SQR(imag->data.F32[i])); 136 } 137 psFree(imag); 138 139 return real; 140 } 141 142 bool psVectorComplexMultiply(psVector **outReal, psVector **outImag, 143 const psVector *in1Real, const psVector *in1Imag, 144 const psVector *in2Real, const psVector *in2Imag) 145 { 146 PS_ASSERT_VECTOR_NON_NULL(in1Real, false); 147 PS_ASSERT_VECTOR_NON_NULL(in1Imag, false); 148 PS_ASSERT_VECTOR_NON_NULL(in2Real, false); 149 PS_ASSERT_VECTOR_NON_NULL(in2Imag, false); 150 PS_ASSERT_VECTOR_TYPE(in1Real, PS_TYPE_F32, false); 151 PS_ASSERT_VECTOR_TYPE(in1Imag, PS_TYPE_F32, false); 152 PS_ASSERT_VECTOR_TYPE(in2Real, PS_TYPE_F32, false); 153 PS_ASSERT_VECTOR_TYPE(in2Imag, PS_TYPE_F32, false); 154 PS_ASSERT_VECTORS_SIZE_EQUAL(in1Imag, in1Real, false); 155 PS_ASSERT_VECTORS_SIZE_EQUAL(in2Real, in1Real, false); 156 PS_ASSERT_VECTORS_SIZE_EQUAL(in2Imag, in1Real, false); 157 PS_ASSERT_PTR_NON_NULL(outReal, false); 158 PS_ASSERT_PTR_NON_NULL(outImag, false); 159 if (*outReal) { 160 PS_ASSERT_VECTOR_NON_NULL(*outReal, false); 161 PS_ASSERT_VECTOR_NON_NULL(*outImag, false); 162 } else if (*outImag) { 163 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 164 "If the output real part is provided, the output imaginary part must also be provided."); 165 return false; 52 166 } 53 167 54 numElements = in->n;168 int num = in1Real->n; // Number of elements 55 169 56 out = psVectorCopy(out, in, PS_TYPE_C32);57 out->n = numElements;170 *outReal = psVectorRecycle(*outReal, num, PS_TYPE_F32); 171 *outImag = psVectorRecycle(*outImag, num, PS_TYPE_F32); 58 172 59 if ((direction & PS_FFT_FORWARD) != 0) { 60 plan = fftwf_plan_dft_1d(numElements, 61 (fftwf_complex *) out->data.C32, 62 (fftwf_complex *) out->data.C32, FFTW_FORWARD, P_FFTW_PLAN_RIGOR); 63 } else if ((direction & PS_FFT_REVERSE) != 0) { 64 plan = fftwf_plan_dft_1d(numElements, 65 (fftwf_complex *) out->data.C32, 66 (fftwf_complex *) out->data.C32, FFTW_BACKWARD, P_FFTW_PLAN_RIGOR); 67 } else { 68 psError(PS_ERR_BAD_PARAMETER_VALUE, true, 69 _("Must specify the direction as either PS_FFT_FORWARD or PS_FFT_REVERSE.")); 70 psFree(out); 71 return NULL; 173 for (int i = 0; i < num; i++) { 174 // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i 175 (*outReal)->data.F32[i] = in1Real->data.F32[i] * in2Real->data.F32[i] - 176 in1Imag->data.F32[i] * in2Imag->data.F32[i]; 177 (*outImag)->data.F32[i] = in1Imag->data.F32[i] * in2Real->data.F32[i] + 178 in1Real->data.F32[i] * in2Imag->data.F32[i]; 72 179 } 73 180 74 /* check if a plan exists now */ 75 if (plan == NULL) { 76 psError(PS_ERR_BAD_PARAMETER_TYPE, true, 77 _("Could not create a valid FFT plan to perform the transform.")); 78 psFree(out); 79 return NULL; 80 } 81 82 /* finally, call FFTW with the plan made above */ 83 fftwf_execute(plan); 84 85 fftwf_destroy_plan(plan); 86 87 if ((direction & PS_FFT_REAL_RESULT) != 0) { 88 for (psS32 i = 0; i < numElements; i++) { 89 out->data.F32[i] = out->data.C32[i]; 90 } 91 out->type.type = PS_TYPE_F32; 92 out->data.U8 = psRealloc(out->data.U8,PSELEMTYPE_SIZEOF(PS_TYPE_F32)*out->nalloc); 93 } 94 95 return out; 181 return true; 96 182 } 97 98 psVector* psVectorReal(psVector* out, const psVector* in)99 {100 psElemType type;101 psU32 numElements;102 103 if (in == NULL) {104 psFree(out);105 return NULL;106 }107 108 type = in->type.type;109 numElements = in->n;110 111 /* if not a complex number, this is logically just a copy */112 if (!PS_IS_PSELEMTYPE_COMPLEX(type)) {113 // Warn user, as this is probably not expected114 psLogMsg(__func__, PS_LOG_WARN, "Real portion of a non-Complex type called called for. "115 "Just a vector copy was performed.");116 out = psVectorRecycle(out, numElements, type);117 out->n = numElements;118 memcpy(out->data.U8, in->data.U8, numElements * PSELEMTYPE_SIZEOF(type));119 return out;120 }121 122 if (type == PS_TYPE_C32) {123 psF32* outVec;124 psC32* inVec = in->data.C32;125 126 out = psVectorRecycle(out, numElements, PS_TYPE_F32);127 out->n = numElements;128 outVec = out->data.F32;129 130 for (psU32 i = 0; i < numElements; i++) {131 outVec[i] = crealf(inVec[i]);132 }133 } else if (type == PS_TYPE_C64) {134 psF64* outVec;135 psC64* inVec = in->data.C64;136 137 out = psVectorRecycle(out, numElements, PS_TYPE_F64);138 out->n = numElements;139 outVec = out->data.F64;140 141 for (psU32 i = 0; i < numElements; i++) {142 outVec[i] = creal(inVec[i]);143 }144 } else {145 char* typeStr;146 PS_TYPE_NAME(typeStr,type);147 psError(PS_ERR_BAD_PARAMETER_TYPE, true,148 _("Specified psVector type, %s, is not supported."),149 typeStr);150 psFree(out);151 return NULL;152 }153 154 return out;155 }156 157 psVector* psVectorImaginary(psVector* out, const psVector* in)158 {159 psElemType type;160 psU32 numElements;161 162 if (in == NULL) {163 psFree(out);164 return NULL;165 }166 167 type = in->type.type;168 numElements = in->n;169 170 /* if not a complex number, this is logically just zeroed image of same size */171 if (!PS_IS_PSELEMTYPE_COMPLEX(type)) {172 // Warn user, as this is probably not expected173 psLogMsg(__func__, PS_LOG_WARN, "Imaginary portion of a non-Complex type called for. "174 "A zeroed vector was returned.");175 out = psVectorRecycle(out, numElements, type);176 out->n = numElements;177 memset(out->data.U8, 0, PSELEMTYPE_SIZEOF(type) * numElements);178 return out;179 }180 181 if (type == PS_TYPE_C32) {182 psF32* outVec;183 psC32* inVec = in->data.C32;184 185 out = psVectorRecycle(out, numElements, PS_TYPE_F32);186 out->n = numElements;187 outVec = out->data.F32;188 189 for (psU32 i = 0; i < numElements; i++) {190 outVec[i] = cimagf(inVec[i]);191 }192 } else if (type == PS_TYPE_C64) {193 psF64* outVec;194 psC64* inVec = in->data.C64;195 196 out = psVectorRecycle(out, numElements, PS_TYPE_F64);197 out->n = numElements;198 outVec = out->data.F64;199 200 for (psU32 i = 0; i < numElements; i++) {201 outVec[i] = cimag(inVec[i]);202 }203 } else {204 char* typeStr;205 PS_TYPE_NAME(typeStr,type);206 psError(PS_ERR_BAD_PARAMETER_TYPE, true,207 _("Specified psVector type, %s, is not supported."),208 typeStr);209 psFree(out);210 return NULL;211 }212 213 return out;214 }215 216 psVector* psVectorComplex(psVector* out, const psVector* real, const psVector* imag)217 {218 psElemType type;219 psU32 numElements;220 221 if (real == NULL || imag == NULL) {222 psFree(out);223 return NULL;224 }225 226 type = real->type.type;227 if (real->n < imag->n) {228 numElements = real->n;229 } else {230 numElements = imag->n;231 }232 233 if (imag->type.type != type) {234 char* typeStrReal;235 char* typeStrImag;236 PS_TYPE_NAME(typeStrReal,type);237 PS_TYPE_NAME(typeStrImag,imag->type.type);238 psError(PS_ERR_BAD_PARAMETER_TYPE, true,239 _("Real psVector type, %s, and imaginary psVector type, %s, must be the same."),240 typeStrReal,typeStrImag);241 psFree(out);242 return NULL;243 }244 245 if (type == PS_TYPE_F32) {246 psC32* outVec;247 psF32* realVec = real->data.F32;248 psF32* imagVec = imag->data.F32;249 250 out = psVectorRecycle(out, numElements, PS_TYPE_C32);251 out->n = numElements;252 outVec = out->data.C32;253 254 for (psU32 i = 0; i < numElements; i++) {255 outVec[i] = realVec[i] + I * imagVec[i];256 }257 } else if (type == PS_TYPE_F64) {258 psC64* outVec;259 psF64* realVec = real->data.F64;260 psF64* imagVec = imag->data.F64;261 262 out = psVectorRecycle(out, numElements, PS_TYPE_C64);263 out->n = numElements;264 outVec = out->data.C64;265 266 for (psU32 i = 0; i < numElements; i++) {267 outVec[i] = realVec[i] + I * imagVec[i];268 }269 } else {270 char* typeStr;271 PS_TYPE_NAME(typeStr,type);272 psError(PS_ERR_BAD_PARAMETER_TYPE, true,273 _("Input psVector type, %s, is required to be either psF32 or psF64."),274 typeStr);275 psFree(out);276 return NULL;277 }278 279 return out;280 }281 282 psVector* psVectorConjugate(psVector* out, const psVector* in)283 {284 psElemType type;285 psU32 numElements;286 287 if (in == NULL) {288 psFree(out);289 return NULL;290 }291 292 type = in->type.type;293 numElements = in->n;294 295 /* if not a complex number, this is logically just a image copy */296 if (!PS_IS_PSELEMTYPE_COMPLEX(type)) {297 // Warn user, as this is probably not expected298 psLogMsg(__func__, PS_LOG_WARN, "Complex Conjugate of a non-Complex type called for. "299 "Vector copy was performed instead.");300 301 out = psVectorRecycle(out, numElements, type);302 out->n = numElements;303 memcpy(out->data.U8, in->data.U8, PSELEMTYPE_SIZEOF(type) * numElements);304 return out;305 }306 307 if (type == PS_TYPE_C32) {308 psC32* outVec;309 psC32* inVec = in->data.C32;310 311 out = psVectorRecycle(out, numElements, PS_TYPE_C32);312 out->n = numElements;313 outVec = out->data.C32;314 315 for (psU32 i = 0; i < numElements; i++) {316 outVec[i] = crealf(inVec[i]) - I * cimagf(inVec[i]);317 }318 } else if (type == PS_TYPE_C64) {319 psC64* outVec;320 psC64* inVec = in->data.C64;321 322 out = psVectorRecycle(out, numElements, PS_TYPE_C64);323 out->n = numElements;324 outVec = out->data.C64;325 326 for (psU32 i = 0; i < numElements; i++) {327 outVec[i] = creal(inVec[i]) - I * cimag(inVec[i]);328 }329 } else {330 char* typeStr;331 PS_TYPE_NAME(typeStr,type);332 psError(PS_ERR_BAD_PARAMETER_TYPE, true,333 _("Input psVector type, %s, is required to be either psC32 or psC64."),334 typeStr);335 psFree(out);336 return NULL;337 }338 339 return out;340 }341 342 psVector* psVectorPowerSpectrum(psVector* out, const psVector* in)343 {344 psElemType type;345 psU32 outNumElements;346 psU32 inNumElements;347 psU32 inHalfNumElements;348 psU32 inNumElementsSquared;349 350 if (in == NULL) {351 psFree(out);352 return NULL;353 }354 355 type = in->type.type;356 inNumElements = in->n;357 inNumElementsSquared = inNumElements * inNumElements;358 inHalfNumElements = inNumElements / 2;359 outNumElements = inHalfNumElements + 1;360 361 if (type == PS_TYPE_C32) {362 psF32* outVec;363 psC32* inVec = in->data.C32;364 psF32 inAbs1;365 psF32 inAbs2;366 367 out = psVectorRecycle(out, outNumElements, PS_TYPE_F32);368 out->n = outNumElements;369 outVec = out->data.F32;370 371 // from ADD: P_0 = |C_0|^2/N^2372 inAbs1 = cabsf(inVec[0]);373 outVec[0] = inAbs1 * inAbs1 / inNumElementsSquared;374 375 // from ADD: P_j = (|C_j|^2+|C_N-j|^2)/N^2, where j = 1,2,...,(N/2-1)376 for (psU32 i = 1; i < inHalfNumElements; i++) {377 inAbs1 = cabsf(inVec[i]);378 inAbs2 = cabsf(inVec[inNumElements - i]);379 outVec[i] = (inAbs1 * inAbs1 + inAbs2 * inAbs2) / inNumElementsSquared;380 }381 382 // from ADD: P_N/2 = |C_N/2|^2/N^2383 inAbs1 = cabsf(inVec[inHalfNumElements]);384 outVec[inHalfNumElements] = inAbs1 * inAbs1 / inNumElementsSquared;385 } else if (type == PS_TYPE_C64) {386 psF64* outVec;387 psC64* inVec = in->data.C64;388 psF64 inAbs1;389 psF64 inAbs2;390 391 out = psVectorRecycle(out, outNumElements, PS_TYPE_F64);392 out->n = outNumElements;393 outVec = out->data.F64;394 395 // from ADD: P_0 = |C_0|^2/N^2396 inAbs1 = cabs(inVec[0]);397 outVec[0] = inAbs1 * inAbs1 / inNumElementsSquared;398 399 // from ADD: P_j = (|C_j|^2+|C_N-j|^2)/N^2, where j = 1,2,...,(N/2-1)400 for (psU32 i = 1; i < inHalfNumElements; i++) {401 inAbs1 = cabs(inVec[i]);402 inAbs2 = cabs(inVec[inNumElements - i]);403 outVec[i] = (inAbs1 * inAbs1 + inAbs2 * inAbs2) / inNumElementsSquared;404 }405 406 // from ADD: P_N/2 = |C_N/2|^2/N^2407 inAbs1 = cabs(inVec[inHalfNumElements]);408 outVec[inHalfNumElements] = inAbs1 * inAbs1 / inNumElementsSquared;409 } else {410 char* typeStr;411 PS_TYPE_NAME(typeStr,type);412 psError(PS_ERR_BAD_PARAMETER_TYPE, true,413 _("Input psVector type, %s, is required to be either psC32 or psC64."),414 typeStr);415 psFree(out);416 return NULL;417 }418 419 return out;420 421 } -
trunk/psLib/src/fft/psVectorFFT.h
r11248 r11703 1 /* @file psVectorFFT.h 2 * @brief Contains FFT transform related functions for psVector 3 * 4 * @author Robert DeSonia, MHPCC 5 * 6 * @version $Revision: 1.19 $ $Name: not supported by cvs2svn $ 7 * @date $Date: 2007-01-23 22:47:22 $ 8 * Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 9 */ 1 /// @file psVectorFFT.h 2 /// @brief Contains FFT transform related functions for psVector 3 /// 4 /// @author Paul Price, IfA 5 /// @author Robert DeSonia, MHPCC 6 /// 7 /// @version $Revision: 1.20 $ $Name: not supported by cvs2svn $ 8 /// @date $Date: 2007-02-08 04:17:58 $ 9 /// Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii 10 /// 10 11 11 12 #ifndef PS_VECTOR_FFT_H … … 17 18 /// @{ 18 19 19 /** Specify direction of FFT */ 20 typedef enum { 21 /// psImageFFT/psVectorFFT should perform a forward FFT. 22 PS_FFT_FORWARD = 1, 20 /// Forward FFT of a vector 21 /// 22 /// Applies a forward FFT (exponent -1), with the result returned in both real and imaginary parts. The FFT 23 /// is not normalised (a forward followed by a reverse is the original scaled by the number of elements). The 24 /// FFT takes advantage of the fact that the input is purely real; hence the output size is N/2 + 1 (with 25 /// division rounding down). Only implemented for F32 input. 26 bool psVectorForwardFFT(psVector **real,///< Real part of FFT 27 psVector **imag,///< Imaginary part of FFT 28 const psVector *in ///< Input vector (F32) 29 ); 23 30 24 /// psImageFFT/psVectorFFT should perform a reverse FFT. 25 PS_FFT_REVERSE = 2, 31 /// Backward FFT of a vector 32 /// 33 /// Applies a backward FFT (exponent +1) from the real and imaginary parts with the (purely) real result 34 /// returned. The FFT is not normalised (a forward followed by a reverse is the original scaled by the number 35 /// of elements). The FFT takes advantage of the fact that the output will be purely real; hence the input 36 /// size is N/2 + 1 (with division rounding down); to manage the redundancy (is the original size even or 37 /// odd?), we need the original size (the size of the array that was input to psVectorForwardFFT) to be 38 /// provided. Only implemented for F32 input. 39 bool psVectorBackwardFFT(psVector **out,///< Output vector 40 const psVector *real, ///< Real input (F32) 41 const psVector *imag, ///< Imaginary input (F32) 42 int origN ///< Original number of elements 43 ); 26 44 27 /// psImageFFT/psVectorFFT should perform a reverse FFT with a real result. 28 PS_FFT_REAL_RESULT = 4 29 } psFFTFlags; 45 /// Power spectrum of a vector 46 /// 47 /// Generates the power spectrum of a vector. Only implemented for F32 input. 48 psVector *psVectorPowerSpectrum(psVector *out, ///< Output power spectrum, or NULL 49 const psVector* in ///< Input vector (F32) 50 ); 30 51 31 32 /** Forward and reverse FFT calculations. 33 * 34 * This takes as input the vector of interest (in) and the direction 35 * (direction), which is specified by an enumerated type psFftDirection. 36 * The input vector may be of type psF32 or psC32, the result is always 37 * psC32. If the input vector is psF32, the direction must be forward. 38 * 39 * @return psVector* the FFT transformation result 40 */ 41 psVector* psVectorFFT( 42 psVector* out, ///< a psVector to recycle. If NULL, a new psVector is made. 43 const psVector* in, ///< the vector to apply transform to 44 psFFTFlags direction ///< the direction of the transform 45 ); 46 47 /** extract the real portion of a complex vector 48 * 49 * @return psVector* real portion of the input vector. 50 */ 51 psVector* psVectorReal( 52 psVector* out, ///< a psVector to recycle. If NULL, a new psVector is made. 53 const psVector* in ///< the psVector to extract real portion from 54 ); 55 56 /** extract the imaginary portion of a complex vector 57 * 58 * @return psVector* imaginary portion of the input vector. 59 */ 60 psVector* psVectorImaginary( 61 psVector* out, ///< a psVector to recycle. If NULL, a new psVector is made. 62 const psVector* in ///< the psVector to extract imaginary portion from 63 ); 64 65 /** creates a complex vector from separate real and imaginary vectors 66 * 67 * @return psVector* resulting complex vector 68 */ 69 psVector* psVectorComplex( 70 psVector* out, ///< a psVector to recycle. If NULL, a new psVector is made. 71 const psVector* real, ///< the real vector 72 const psVector* imag ///< the imaginary vector 73 ); 74 75 /** computes the complex conjugate of a vector 76 * 77 * @return psVector* the complex conjugate of the 'in' vector 78 */ 79 psVector* psVectorConjugate( 80 psVector* out, ///< a psVector to recycle. If NULL, a new psVector is made. 81 const psVector* in ///< the psVector to compute conjugate of 82 ); 83 84 /** computes the power spectrum of a vector 85 * 86 * @return psVector* the power spectrum of the 'in' vector 87 */ 88 psVector* psVectorPowerSpectrum( 89 psVector* out, ///< a psVector to recycle. If NULL, a new psVector is made. 90 const psVector* in ///< the psVector to power spectrum of 91 ); 52 /// Multiply complex vectors 53 /// 54 /// The input vectors are the real and imaginary parts of each of two vectors. The real and imaginary parts 55 /// of the output vector are returned. Only implemented for F32 input. 56 bool psVectorComplexMultiply(psVector **outReal, ///< Real part of output 57 psVector **outImag, ///< Imaginary part of output 58 const psVector *in1Real, ///< Real part of input 1 59 const psVector *in1Imag, ///< Imaginary part of input 1 60 const psVector *in2Real, ///< Real part of input 2 61 const psVector *in2Imag ///< Imaginary part of input 2 62 ); 92 63 93 64 /// @}
Note:
See TracChangeset
for help on using the changeset viewer.
