JWS C Library
C language utility library
|
00001 /* 00002 * This work is licensed under a Creative Commons 00003 * Attribution-Noncommercial-Share Alike 3.0 United States License. 00004 * 00005 * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ 00006 * 00007 * You are free: 00008 * 00009 * to Share - to copy, distribute, display, and perform the work 00010 * to Remix - to make derivative works 00011 * 00012 * Under the following conditions: 00013 * 00014 * Attribution. You must attribute the work in the manner specified by the 00015 * author or licensor (but not in any way that suggests that they endorse you 00016 * or your use of the work). 00017 * 00018 * Noncommercial. You may not use this work for commercial purposes. 00019 * 00020 * Share Alike. If you alter, transform, or build upon this work, you may 00021 * distribute the resulting work only under the same or similar license to 00022 * this one. 00023 * 00024 * For any reuse or distribution, you must make clear to others the license 00025 * terms of this work. The best way to do this is by including this header. 00026 * 00027 * Any of the above conditions can be waived if you get permission from the 00028 * copyright holder. 00029 * 00030 * Apart from the remix rights granted under this license, nothing in this 00031 * license impairs or restricts the author's moral rights. 00032 */ 00033 00034 00046 #include <jwsc/config.h> 00047 00048 #include <stdlib.h> 00049 #include <inttypes.h> 00050 #include <math.h> 00051 #include <assert.h> 00052 00053 #include "jwsc/base/error.h" 00054 #include "jwsc/matblock/matblock.h" 00055 #include "jwsc/matblock/matblock_math.h" 00056 #include "jwsc/matblock/matblock_fft.h" 00057 #include "jwsc/matblock/matblock_conv.h" 00058 00059 00061 #define PI 3.14159265358979323846 00062 00063 00097 Error* convolve_matblock_f 00098 ( 00099 Matblock_f** m_out, 00100 const Matblock_f* m_in, 00101 const Matblock_f* h 00102 ) 00103 { 00104 int64_t num_in_mats, num_in_rows, num_in_cols; /* 64-bit since signed */ 00105 int64_t num_h_mats, num_h_rows, num_h_cols; 00106 int64_t in_mat, in_row, in_col; 00107 int64_t h_mat, h_row, h_col; 00108 int64_t h_mat_center; 00109 int64_t h_row_center; 00110 int64_t h_col_center; 00111 int64_t i, j, k; 00112 00113 float sum; 00114 Matblock_f* m; 00115 00116 num_in_mats = m_in->num_mats; 00117 num_in_rows = m_in->num_rows; 00118 num_in_cols = m_in->num_cols; 00119 num_h_mats = h->num_mats; 00120 num_h_rows = h->num_rows; 00121 num_h_cols = h->num_cols; 00122 00123 /* Test if the filter is larger than m_in. */ 00124 if (num_in_mats < num_h_mats || 00125 num_in_rows < num_h_rows || 00126 num_in_cols < num_h_cols) 00127 { 00128 if (*m_out != m_in) 00129 { 00130 free_matblock_f(*m_out); *m_out = NULL; 00131 } 00132 return JWSC_EARG("Convolution filter larger than input matblock"); 00133 } 00134 00135 m = (*m_out == m_in) ? NULL : *m_out; 00136 create_matblock_f(&m, num_in_mats, num_in_rows, num_in_cols); 00137 00138 h_mat_center = num_h_mats / 2; 00139 h_row_center = num_h_rows / 2; 00140 h_col_center = num_h_cols / 2; 00141 00142 for (in_mat = 0; in_mat < num_in_mats; in_mat++) 00143 { 00144 for (in_row = 0; in_row < num_in_rows; in_row++) 00145 { 00146 for (in_col = 0; in_col < num_in_cols; in_col++) 00147 { 00148 sum = 0; 00149 for (h_mat = 0; h_mat < num_h_mats; h_mat++) 00150 { 00151 for (h_row = 0; h_row < num_h_rows; h_row++) 00152 { 00153 for (h_col = 0; h_col < num_h_cols; h_col++) 00154 { 00155 i = in_mat + (h_mat - h_mat_center); 00156 if (i < 0) 00157 { 00158 i = -i; 00159 } 00160 else if (i >= num_in_mats) 00161 { 00162 i = num_in_mats - (i - (num_in_mats - 1)); 00163 } 00164 00165 j = in_row + (h_row - h_row_center); 00166 if (j < 0) 00167 { 00168 j = -j; 00169 } 00170 else if (j >= num_in_rows) 00171 { 00172 j = num_in_rows - (j - (num_in_rows - 1)); 00173 } 00174 00175 k = in_col + (h_col - h_col_center); 00176 if (k < 0) 00177 { 00178 k = -k; 00179 } 00180 else if (k >= num_in_cols) 00181 { 00182 k = num_in_cols - (k - (num_in_cols - 1)); 00183 } 00184 00185 sum += m_in->elts[ i ][ j ][ k ] * 00186 h->elts[ h_mat ][ h_row ][ h_col ]; 00187 } 00188 } 00189 } 00190 m->elts[ in_mat ][ in_row ][ in_col ] = sum; 00191 } 00192 } 00193 } 00194 00195 if (*m_out == m_in) 00196 { 00197 copy_matblock_f(m_out, m); 00198 free_matblock_f(m); 00199 } 00200 else 00201 { 00202 *m_out = m; 00203 } 00204 00205 return NULL; 00206 } 00207 00234 Error* convolve_matblock_d 00235 ( 00236 Matblock_d** m_out, 00237 const Matblock_d* m_in, 00238 const Matblock_d* h 00239 ) 00240 { 00241 int64_t num_in_mats, num_in_rows, num_in_cols; /* 64-bit since signed */ 00242 int64_t num_h_mats, num_h_rows, num_h_cols; 00243 int64_t in_mat, in_row, in_col; 00244 int64_t h_mat, h_row, h_col; 00245 int64_t h_mat_center; 00246 int64_t h_row_center; 00247 int64_t h_col_center; 00248 int64_t i, j, k; 00249 00250 double sum; 00251 Matblock_d* m; 00252 00253 num_in_mats = m_in->num_mats; 00254 num_in_rows = m_in->num_rows; 00255 num_in_cols = m_in->num_cols; 00256 num_h_mats = h->num_mats; 00257 num_h_rows = h->num_rows; 00258 num_h_cols = h->num_cols; 00259 00260 /* Test if the filter is larger than m_in. */ 00261 if (num_in_mats < num_h_mats || 00262 num_in_rows < num_h_rows || 00263 num_in_cols < num_h_cols) 00264 { 00265 if (*m_out != m_in) 00266 { 00267 free_matblock_d(*m_out); *m_out = NULL; 00268 } 00269 return JWSC_EARG("Convolution filter larger than input matblock"); 00270 } 00271 00272 m = (*m_out == m_in) ? NULL : *m_out; 00273 create_matblock_d(&m, num_in_mats, num_in_rows, num_in_cols); 00274 00275 h_mat_center = num_h_mats / 2; 00276 h_row_center = num_h_rows / 2; 00277 h_col_center = num_h_cols / 2; 00278 00279 for (in_mat = 0; in_mat < num_in_mats; in_mat++) 00280 { 00281 for (in_row = 0; in_row < num_in_rows; in_row++) 00282 { 00283 for (in_col = 0; in_col < num_in_cols; in_col++) 00284 { 00285 sum = 0; 00286 for (h_mat = 0; h_mat < num_h_mats; h_mat++) 00287 { 00288 for (h_row = 0; h_row < num_h_rows; h_row++) 00289 { 00290 for (h_col = 0; h_col < num_h_cols; h_col++) 00291 { 00292 i = in_mat + (h_mat - h_mat_center); 00293 if (i < 0) 00294 { 00295 i = -i; 00296 } 00297 else if (i >= num_in_mats) 00298 { 00299 i = num_in_mats - (i - (num_in_mats - 1)); 00300 } 00301 00302 j = in_row + (h_row - h_row_center); 00303 if (j < 0) 00304 { 00305 j = -j; 00306 } 00307 else if (j >= num_in_rows) 00308 { 00309 j = num_in_rows - (j - (num_in_rows - 1)); 00310 } 00311 00312 k = in_col + (h_col - h_col_center); 00313 if (k < 0) 00314 { 00315 k = -k; 00316 } 00317 else if (k >= num_in_cols) 00318 { 00319 k = num_in_cols - (k - (num_in_cols - 1)); 00320 } 00321 00322 sum += m_in->elts[ i ][ j ][ k ] * 00323 h->elts[ h_mat ][ h_row ][ h_col ]; 00324 } 00325 } 00326 } 00327 m->elts[ in_mat ][ in_row ][ in_col ] = sum; 00328 } 00329 } 00330 } 00331 00332 if (*m_out == m_in) 00333 { 00334 copy_matblock_d(m_out, m); 00335 free_matblock_d(m); 00336 } 00337 else 00338 { 00339 *m_out = m; 00340 } 00341 00342 return NULL; 00343 } 00344 00377 #ifdef JWSC_HAVE_FFTW3F 00378 Error* convolve_matblock_fft_f 00379 ( 00380 Matblock_f** m_out, 00381 const Matblock_f* m_in, 00382 const Matblock_f* h 00383 ) 00384 { 00385 Matblock_cf* s_1 = NULL; 00386 Matblock_cf* s_2 = NULL; 00387 Matblock_f* s_3 = NULL; 00388 Matblock_cf* s_4 = NULL; 00389 00390 convolve_matblock_fft_scratch_f(m_out, m_in, h, &s_1, &s_2, &s_3, &s_4); 00391 00392 free_matblock_cf(s_1); 00393 free_matblock_cf(s_2); 00394 free_matblock_f(s_3); 00395 free_matblock_cf(s_4); 00396 00397 return NULL; 00398 } 00399 #endif 00400 00421 #ifdef JWSC_HAVE_FFTW3F 00422 Error* convolve_matblock_fft_d 00423 ( 00424 Matblock_d** m_out, 00425 const Matblock_d* m_in, 00426 const Matblock_d* h 00427 ) 00428 { 00429 Matblock_cd* s_1 = NULL; 00430 Matblock_cd* s_2 = NULL; 00431 Matblock_d* s_3 = NULL; 00432 Matblock_cd* s_4 = NULL; 00433 00434 convolve_matblock_fft_scratch_d(m_out, m_in, h, &s_1, &s_2, &s_3, &s_4); 00435 00436 free_matblock_cd(s_1); 00437 free_matblock_cd(s_2); 00438 free_matblock_d(s_3); 00439 free_matblock_cd(s_4); 00440 00441 return NULL; 00442 } 00443 #endif 00444 00481 #ifdef JWSC_HAVE_FFTW3F 00482 Error* convolve_matblock_fft_scratch_f 00483 ( 00484 Matblock_f** m_out, 00485 const Matblock_f* m_in, 00486 const Matblock_f* h, 00487 Matblock_cf** s_1, 00488 Matblock_cf** s_2, 00489 Matblock_f** s_3, 00490 Matblock_cf** s_4 00491 ) 00492 { 00493 uint32_t num_in_mats, num_in_rows, num_in_cols; 00494 uint32_t num_h_mats, num_h_rows, num_h_cols; 00495 00496 num_in_mats = m_in->num_mats; 00497 num_in_rows = m_in->num_rows; 00498 num_in_cols = m_in->num_cols; 00499 num_h_mats = h->num_mats; 00500 num_h_rows = h->num_rows; 00501 num_h_cols = h->num_cols; 00502 00503 /* Test if the filter is the same size as m_in. */ 00504 if (num_in_mats != num_h_mats || 00505 num_in_rows != num_h_rows || 00506 num_in_cols != num_h_cols) 00507 { 00508 if (*m_out != m_in) 00509 { 00510 free_matblock_f(*m_out); *m_out = NULL; 00511 } 00512 return JWSC_EARG("Incompatible matblock sizes for FFT convolution"); 00513 } 00514 00515 real_to_complex_matblock_dft_scratch_f(s_1, m_in, s_3); 00516 real_to_complex_matblock_dft_scratch_f(s_2, h, s_3); 00517 assert(multiply_matblocks_elt_wise_cf(s_1, *s_1, *s_2) == NULL); 00518 complex_to_real_matblock_dft_scratch_f(m_out, *s_1, 00519 (num_in_cols % 2 == 0), s_4); 00520 scale_matblock_dft_f(m_out, *m_out); 00521 00522 return NULL; 00523 } 00524 #endif 00525 00550 #ifdef JWSC_HAVE_FFTW3F 00551 Error* convolve_matblock_fft_scratch_d 00552 ( 00553 Matblock_d** m_out, 00554 const Matblock_d* m_in, 00555 const Matblock_d* h, 00556 Matblock_cd** s_1, 00557 Matblock_cd** s_2, 00558 Matblock_d** s_3, 00559 Matblock_cd** s_4 00560 ) 00561 { 00562 uint32_t num_in_mats, num_in_rows, num_in_cols; 00563 uint32_t num_h_mats, num_h_rows, num_h_cols; 00564 00565 num_in_mats = m_in->num_mats; 00566 num_in_rows = m_in->num_rows; 00567 num_in_cols = m_in->num_cols; 00568 num_h_mats = h->num_mats; 00569 num_h_rows = h->num_rows; 00570 num_h_cols = h->num_cols; 00571 00572 /* Test if the filter is the same size as m_in. */ 00573 if (num_in_mats != num_h_mats || 00574 num_in_rows != num_h_rows || 00575 num_in_cols != num_h_cols) 00576 { 00577 if (*m_out != m_in) 00578 { 00579 free_matblock_d(*m_out); *m_out = NULL; 00580 } 00581 return JWSC_EARG("Incompatible matblock size for FFT convolution"); 00582 } 00583 00584 real_to_complex_matblock_dft_scratch_d(s_1, m_in, s_3); 00585 real_to_complex_matblock_dft_scratch_d(s_2, h, s_3); 00586 assert(multiply_matblocks_elt_wise_cd(s_1, *s_1, *s_2) == NULL); 00587 complex_to_real_matblock_dft_scratch_d(m_out, *s_1, 00588 (num_in_cols % 2 == 0), s_4); 00589 scale_matblock_dft_d(m_out, *m_out); 00590 00591 return NULL; 00592 } 00593 #endif 00594