Wavelet* copy_wavelet(Wavelet* base) { Wavelet* w; index_t i; if(base == NULL) return NULL; if(base->dec_len < 1 || base->rec_len < 1) return NULL; w = wtmalloc(sizeof(Wavelet)); if(w == NULL) return NULL; memcpy(w, base, sizeof(Wavelet)); w->_builtin = 0; w->dec_lo_double = wtcalloc(w->dec_len, sizeof(double)); w->dec_hi_double = wtcalloc(w->dec_len, sizeof(double)); w->rec_lo_double = wtcalloc(w->rec_len, sizeof(double)); w->rec_hi_double = wtcalloc(w->rec_len, sizeof(double)); if(w->dec_lo_double == NULL || w->dec_hi_double == NULL || w->rec_lo_double == NULL || w->rec_hi_double == NULL){ free_wavelet(w); return NULL; } for(i=0; i< w->dec_len; ++i){ w->dec_lo_double[i] = base->dec_lo_double[i]; w->dec_hi_double[i] = base->dec_hi_double[i]; } for(i=0; i< w->rec_len; ++i){ w->rec_lo_double[i] = base->rec_lo_double[i]; w->rec_hi_double[i] = base->rec_hi_double[i]; } w->dec_lo_float = wtcalloc(w->dec_len, sizeof(float)); w->dec_hi_float = wtcalloc(w->dec_len, sizeof(float)); w->rec_lo_float = wtcalloc(w->rec_len, sizeof(float)); w->rec_hi_float = wtcalloc(w->rec_len, sizeof(float)); if(w->dec_lo_float == NULL || w->dec_hi_float == NULL || w->rec_lo_float == NULL || w->rec_hi_float == NULL){ free_wavelet(w); return NULL; } for(i=0; i< w->dec_len; ++i){ w->dec_lo_float[i] = base->dec_lo_float[i]; w->dec_hi_float[i] = base->dec_hi_float[i]; } for(i=0; i< w->rec_len; ++i){ w->rec_lo_float[i] = base->rec_lo_float[i]; w->rec_hi_float[i] = base->rec_hi_float[i]; } return w; }
Wavelet* blank_wavelet(index_t filters_length) { Wavelet* w; if(filters_length < 1) return NULL; // pad to even length if(filters_length % 2) ++filters_length; w = wtmalloc(sizeof(Wavelet)); if(w == NULL) return NULL; //w->dec_lo_offset = w->rec_lo_offset = 0; //w->dec_hi_offset = w->rec_hi_offset = 0; // Important! // Otherwise filters arrays allocated here won't be deallocated by free_wavelet w->_builtin = 0; w->dec_len = w->rec_len = filters_length; w->dec_lo_double = wtcalloc(filters_length, sizeof(double)); w->dec_hi_double = wtcalloc(filters_length, sizeof(double)); w->rec_lo_double = wtcalloc(filters_length, sizeof(double)); w->rec_hi_double = wtcalloc(filters_length, sizeof(double)); if(w->dec_lo_double == NULL || w->dec_hi_double == NULL || w->rec_lo_double == NULL || w->rec_hi_double == NULL){ free_wavelet(w); return NULL; } w->dec_lo_float = wtcalloc(filters_length, sizeof(float)); w->dec_hi_float = wtcalloc(filters_length, sizeof(float)); w->rec_lo_float = wtcalloc(filters_length, sizeof(float)); w->rec_hi_float = wtcalloc(filters_length, sizeof(float)); if(w->dec_lo_float == NULL || w->dec_hi_float == NULL || w->rec_lo_float == NULL || w->rec_hi_float == NULL){ free_wavelet(w); return NULL; } // set properties to "blank" values w->vanishing_moments_psi = 0; w->vanishing_moments_phi = 0; w->support_width = -1; w->orthogonal = 0; w->biorthogonal = 0; w->symmetry = UNKNOWN; w->compact_support = 0; w->family_name = ""; w->short_name = ""; return w; }
int main(){ // Using C API to decompose 1D signal. // Results equivalent to pywt.dwt([1,2,3,4,5,6,7,8], 'db2', 'zpd'). // Compile: gcc -I../src dwt_decompose.c ../src/wt.c ../src/wavelets.c ../src/common.c ../src/convolution.c Wavelet *w = wavelet('d', 2); MODE mode = MODE_ZEROPAD; int i; float input[] = {1,2,3,4,5,6,7,8,9}; float *cA, *cD; index_t input_len, output_len; input_len = sizeof input / sizeof input[0]; output_len = dwt_buffer_length(input_len, w->dec_len, mode); cA = wtcalloc(output_len, sizeof(float)); cD = wtcalloc(output_len, sizeof(float)); printf("Wavelet: %s %d\n\n", w->family_name, w->vanishing_moments_psi); float_dec_a(input, input_len, w, cA, output_len, mode); float_dec_d(input, input_len, w, cD, output_len, mode); for(i=0; i<output_len; i++){ printf("%f ", cA[i]); } printf("\n\n"); for(i=0; i<output_len; i++){ printf("%f ", cD[i]); } printf("\n"); free_wavelet(w); wtfree(cA); wtfree(cD); return 0; }
// basic SWT step // TODO: optimize INLINE int float_swt_(float input[], index_t input_len, const float filter[], index_t filter_len, float output[], index_t output_len, int level){ float* e_filter; index_t i, e_filter_len; if(level < 1) return -1; if(level > swt_max_level(input_len)) return -2; if(output_len != swt_buffer_length(input_len)) return -1; // TODO: quick hack, optimize if(level > 1){ // allocate filter first e_filter_len = filter_len << (level-1); e_filter = wtcalloc(e_filter_len, sizeof(float)); if(e_filter == NULL) return -1; // compute upsampled filter values for(i = 0; i < filter_len; ++i){ e_filter[i << (level-1)] = filter[i]; } i = float_downsampling_convolution(input, input_len, e_filter, e_filter_len, output, 1, MODE_PERIODIZATION); wtfree(e_filter); return i; } else { return float_downsampling_convolution(input, input_len, filter, filter_len, output, 1, MODE_PERIODIZATION); } }
int $DTYPE$_upsampling_convolution_valid_sf_periodization(const $DTYPE$* input, const_index_t N, const $DTYPE$* filter, const_index_t F, $DTYPE$* output, const_index_t O) { $DTYPE$ *ptr_out = output; $DTYPE$ *filter_even, *filter_odd; $DTYPE$ *periodization_buf = NULL; $DTYPE$ *periodization_buf_rear = NULL; $DTYPE$ *ptr_base; $DTYPE$ sum_even, sum_odd; index_t i, j, k, N_p = 0; index_t F_2 = F/2; if(F%2) return -3; // Filter must have even-length. /////////////////////////////////////////////////////////////////////////// // Handle special situation when input coeff data is shorter than half of // the filter's length. The coeff array has to be extended periodically. // This can be only valid for PERIODIZATION_MODE if(N < F_2) // ======= { // Input data for periodization mode has to be periodically extended // New length for temporary input N_p = F_2-1 +N; // periodization_buf will hold periodically copied input coeffs values periodization_buf = wtcalloc(N_p, sizeof($DTYPE$)); if(periodization_buf == NULL) return -1; // Copy input data to it's place in the periodization_buf // -> [0 0 0 i1 i2 i3 0 0 0] k = (F_2-1)/2; for(i=k; i < k+N; ++i) periodization_buf[i] = input[(i-k)%N]; //if(N%2) // periodization_buf[i++] = input[N-1]; // [0 0 0 i1 i2 i3 0 0 0] // points here ^^ periodization_buf_rear = periodization_buf+i-1; // copy cyclically () to right // [0 0 0 i1 i2 i3 i1 i2 ...] j = i-k; for(; i < N_p; ++i) periodization_buf[i] = periodization_buf[i-j]; // copy cyclically () to left // [... i2 i3 i1 i2 i3 i1 i2 i3] j = 0; for(i=k-1; i >= 0; --i){ periodization_buf[i] = periodization_buf_rear[j]; --j; } // Now perform the valid convolution if(F_2%2){ $DTYPE$_upsampling_convolution_valid_sf(periodization_buf, N_p, filter, F, output, O, MODE_ZEROPAD); // The F_2%2==0 case needs special result fix (oh my, another one..) } else { // Cheap result fix for short inputs // Memory allocation for temporary output is done. // Computed temporary result is copied to output* ptr_out = wtcalloc(idwt_buffer_length(N, F, MODE_PERIODIZATION), sizeof($DTYPE$)); if(ptr_out == NULL){ wtfree(periodization_buf); return -1; } // Convolve here as for (F_2%2) branch above $DTYPE$_upsampling_convolution_valid_sf(periodization_buf, N_p, filter, F, ptr_out, O, MODE_ZEROPAD); // rewrite result to output for(i=2*N-1; i > 0; --i){ output[i] += ptr_out[i-1]; } // and the first element output[0] += ptr_out[2*N-1]; wtfree(ptr_out); // and voil`a!, ugh } } else { // Otherwise (N >= F_2) // Allocate memory for even and odd elements of the filter filter_even = wtmalloc(F_2 * sizeof($DTYPE$)); filter_odd = wtmalloc(F_2 * sizeof($DTYPE$)); if(filter_odd == NULL || filter_odd == NULL){ if(filter_odd == NULL) wtfree(filter_odd); if(filter_even == NULL) wtfree(filter_even); return -1; } // split filter to even and odd values for(i = 0; i < F_2; ++i){ filter_even[i] = filter[i << 1]; filter_odd[i] = filter[(i << 1) + 1]; } /////////////////////////////////////////////////////////////////////////// // This part is quite complicated and has some wild checking to get results // similar to those from Matlab(TM) Wavelet Toolbox k = F_2-1; // Check if extending is really needed N_p = F_2-1 + (index_t) ceil(k/2.); /*split filter len correct. + extra samples*/ // ok, if is then do: // 1. Allocate buffers for front and rear parts of extended input // 2. Copy periodically appriopriate elements from input to the buffers // 3. Convolve front buffer, input and rear buffer with even and odd // elements of the filter (this results in upsampling) // 4. Free memory if(N_p > 0){ // ======= // Allocate memory only for the front and rear extension parts, not the // whole input periodization_buf = wtcalloc(N_p, sizeof($DTYPE$)); periodization_buf_rear = wtcalloc(N_p, sizeof($DTYPE$)); // Memory checking if(periodization_buf == NULL || periodization_buf_rear == NULL){ if(periodization_buf == NULL) wtfree(periodization_buf); if(periodization_buf_rear == NULL) wtfree(periodization_buf_rear); wtfree(filter_odd); wtfree(filter_even); return -1; } // Fill buffers with appriopriate elements memcpy(periodization_buf + N_p - k, input, k * sizeof($DTYPE$)); // copy from beginning of input to end of buffer for(i = 1; i <= (N_p - k); ++i) // kopiowanie 'cykliczne' od końca input periodization_buf[(N_p - k) - i] = input[N - (i%N)]; memcpy(periodization_buf_rear, input + N - k, k * sizeof($DTYPE$)); // copy from end of input to begginning of buffer for(i = 0; i < (N_p - k); ++i) // kopiowanie 'cykliczne' od początku input periodization_buf_rear[k + i] = input[i%N]; /////////////////////////////////////////////////////////////////// // Convolve filters with the (front) periodization_buf and compute // the first part of output ptr_base = periodization_buf + F_2 - 1; if(k%2 == 1){ sum_odd = 0; for(j = 0; j < F_2; ++j) sum_odd += filter_odd[j] * ptr_base[-j]; *(ptr_out++) += sum_odd; --k; if(k) $DTYPE$_upsampling_convolution_valid_sf(periodization_buf + 1, N_p-1, filter, F, ptr_out, O-1, MODE_ZEROPAD); ptr_out += k; // k0 - 1 // really move backward by 1 } else if(k){ $DTYPE$_upsampling_convolution_valid_sf(periodization_buf, N_p, filter, F, ptr_out, O, MODE_ZEROPAD); ptr_out += k; } } /////////////////////////////////////////////////////////////////////////// // Perform _valid_ convolution (only when all filter_even and filter_odd elements // are in range of input data). // // This part is simple, no extra hacks, just two convolutions in one loop ptr_base = ($DTYPE$*)input + F_2 - 1; for(i = 0; i < N-(F_2-1); ++i){ // sliding over signal from left to right sum_even = 0; sum_odd = 0; for(j = 0; j < F_2; ++j){ sum_even += filter_even[j] * ptr_base[i-j]; sum_odd += filter_odd[j] * ptr_base[i-j]; } *(ptr_out++) += sum_even; *(ptr_out++) += sum_odd; } // /////////////////////////////////////////////////////////////////////////// if(N_p > 0){ // ======= k = F_2-1; if(k%2 == 1){ if(F/2 <= N_p - 1){ // k > 1 ? $DTYPE$_upsampling_convolution_valid_sf(periodization_buf_rear , N_p-1, filter, F, ptr_out, O-1, MODE_ZEROPAD); } ptr_out += k; // move forward anyway -> see lower if(F_2%2 == 0){ // remaining one element ptr_base = periodization_buf_rear + N_p - 1; sum_even = 0; for(j = 0; j < F_2; ++j){ sum_even += filter_even[j] * ptr_base[-j]; } *(--ptr_out) += sum_even; // move backward first } } else { if(k){ $DTYPE$_upsampling_convolution_valid_sf(periodization_buf_rear, N_p, filter, F, ptr_out, O, MODE_ZEROPAD); } } } if(periodization_buf != NULL) wtfree(periodization_buf); if(periodization_buf_rear != NULL) wtfree(periodization_buf_rear); wtfree(filter_even); wtfree(filter_odd); } return 0; }
int $DTYPE$_allocating_downsampling_convolution(const $DTYPE$* input, const_index_t N, const $DTYPE$* filter, const_index_t F, $DTYPE$* output, const_index_t step, MODE mode) { index_t i, j, F_minus_1, N_extended_len, N_extended_right_start; index_t start, stop; $DTYPE$ sum, tmp; $DTYPE$ *buffer; $DTYPE$* ptr_w = output; F_minus_1 = F - 1; start = F_minus_1+step-1; // allocate memory and copy input if(mode != MODE_PERIODIZATION){ N_extended_len = N + 2*F_minus_1; N_extended_right_start = N + F_minus_1; buffer = wtcalloc(N_extended_len, sizeof($DTYPE$)); if(buffer == NULL) return -1; memcpy(buffer+F_minus_1, input, sizeof($DTYPE$) * N); stop = N_extended_len; } else { N_extended_len = N + F-1; N_extended_right_start = N-1 + F/2; buffer = wtcalloc(N_extended_len, sizeof($DTYPE$)); if(buffer == NULL) return -1; memcpy(buffer+F/2-1, input, sizeof($DTYPE$) * N); start -= 1; if(step == 1) stop = N_extended_len-1; else // step == 2 stop = N_extended_len; } // copy extended signal elements switch(mode){ case MODE_PERIODIZATION: if(N%2){ // odd - repeat last element buffer[N_extended_right_start] = input[N-1]; for(j = 1; j < F/2; ++j) buffer[N_extended_right_start+j] = buffer[F/2-2 + j]; // copy from begining of `input` to right for(j = 0; j < F/2-1; ++j) // copy from 'buffer' to left buffer[F/2-2-j] = buffer[N_extended_right_start-j]; } else { for(j = 0; j < F/2; ++j) buffer[N_extended_right_start+j] = input[j%N]; // copy from begining of `input` to right for(j = 0; j < F/2-1; ++j) // copy from 'buffer' to left buffer[F/2-2-j] = buffer[N_extended_right_start-1-j]; } break; case MODE_SYMMETRIC: for(j = 0; j < N; ++j){ buffer[F_minus_1-1-j] = input[j%N]; buffer[N_extended_right_start+j] = input[N-1-(j%N)]; } i=j; // use `buffer` as source for(; j < F_minus_1; ++j){ buffer[F_minus_1-1-j] = buffer[N_extended_right_start-1+i-j]; buffer[N_extended_right_start+j] = buffer[F_minus_1+j-i]; } break; case MODE_ASYMMETRIC: for(j = 0; j < N; ++j){ buffer[F_minus_1-1-j] = input[0] - input[j%N]; buffer[N_extended_right_start+j] = (input[N-1] - input[N-1-(j%N)]); } i=j; // use `buffer` as source for(; j < F_minus_1; ++j){ buffer[F_minus_1-1-j] = buffer[N_extended_right_start-1+i-j]; buffer[N_extended_right_start+j] = buffer[F_minus_1+j-i]; } break; case MODE_SMOOTH: if(N>1){ tmp = input[0]-input[1]; for(j = 0; j < F_minus_1; ++j) buffer[j] = input[0] + (tmp * (F_minus_1-j)); tmp = input[N-1]-input[N-2]; for(j = 0; j < F_minus_1; ++j) buffer[N_extended_right_start+j] = input[N-1] + (tmp*j); break; } case MODE_CONSTANT_EDGE: for(j = 0; j < F_minus_1; ++j){ buffer[j] = input[0]; buffer[N_extended_right_start+j] = input[N-1]; } break; case MODE_PERIODIC: for(j = 0; j < F_minus_1; ++j) buffer[N_extended_right_start+j] = input[j%N]; // copy from beggining of `input` to right for(j = 0; j < F_minus_1; ++j) // copy from 'buffer' to left buffer[F_minus_1-1-j] = buffer[N_extended_right_start-1-j]; break; case MODE_ZEROPAD: default: //memset(buffer, 0, sizeof($DTYPE$)*F_minus_1); //memset(buffer+N_extended_right_start, 0, sizeof($DTYPE$)*F_minus_1); //memcpy(buffer+N_extended_right_start, buffer, sizeof($DTYPE$)*F_minus_1); break; } /////////////////////////////////////////////////////////////////////// // F - N-1 - filter in input range // perform convolution with decimation for(i=start; i < stop; i+=step){ // input elements sum = 0; for(j = 0; j < F; ++j){ sum += buffer[i-j]*filter[j]; } *(ptr_w++) = sum; } // free memory wtfree(buffer); return 0; }
int upsampling_convolution_valid_sf(const DTYPE* input, const int N, const double* filter, const int F, double* output, const int O, const int mode){ double *ptr_out = output; double *filter_even, *filter_odd; DTYPE *periodization_buf = NULL, *periodization_buf_rear = NULL; DTYPE *ptr_base; double sum_even, sum_odd; int i, j, k, N_p = 0; int F_2 = F/2; // F/2 if(F%2) return -3; if(F_2 > N){ if(mode == MODE_PERIODIZATION){ N_p = F_2-1 +N; periodization_buf = (double*) wtcalloc(N_p, sizeof(DTYPE)); k = (F_2-1)/2; for(i=k; i < k+N; ++i) periodization_buf[i] = input[(i-k)%N]; //if(N%2) // periodization_buf[i++] = input[N-1]; periodization_buf_rear = periodization_buf+i-1; j = i-k; for(; i < N_p; ++i) periodization_buf[i] = periodization_buf[i-j]; j = 0; for(i=k-1; i >= 0; --i){ periodization_buf[i] = periodization_buf_rear[j]; --j; } if(F_2%2==0){ // cheap result fix ptr_out = (double*) wtcalloc(idwt_buffer_length(N, F, MODE_PERIODIZATION), sizeof(double)); if(ptr_out == NULL) return -3; upsampling_convolution_valid_sf(periodization_buf, N_p, filter, F, ptr_out, O, MODE_ZEROPAD); for(i=2*N-1; i > 0; --i){ output[i] += ptr_out[i-1]; } output[0] += ptr_out[2*N-1]; wtfree(ptr_out); } else { upsampling_convolution_valid_sf(periodization_buf, N_p, filter, F, output, O, MODE_ZEROPAD); } return 0; } else { return -2; // invalid lengths } } // allocate memory for even and odd elements of filter filter_even = (double*) malloc(F_2 * sizeof(double)); filter_odd = (double*) malloc(F_2 * sizeof(double)); if(filter_odd == NULL || filter_odd == NULL){ return -1; } // copy values for(i = 0; i < F_2; ++i){ filter_even[i] = filter[i << 1]; filter_odd[i] = filter[(i << 1) + 1]; } /////////////////////////////////////////////////////////////////////////// // MODE_PERIODIZATION // this part is quite complicated if(mode == MODE_PERIODIZATION){ k = F_2-1; N_p = F_2-1 + (int) ceil(k/2.); /*split filter len correct. + extra samples*/ if(N_p > 0){ periodization_buf = (double*) calloc(N_p, sizeof(double)); periodization_buf_rear = (double*) calloc(N_p, sizeof(double)); if(k <= N){ memcpy(periodization_buf + N_p - k, input, k * sizeof(double)); // copy from beginning of input to end of buffer for(i = 1; i <= (N_p - k); ++i) // kopiowanie 'cykliczne' od koñca input periodization_buf[(N_p - k) - i] = input[N - (i%N)]; memcpy(periodization_buf_rear, input + N - k, k * sizeof(double)); // copy from end of input to begginning of buffer for(i = 0; i < (N_p - k); ++i) // kopiowanie 'cykliczne' od pocz¹tku input periodization_buf_rear[k + i] = input[i%N]; } else { //printf("see %d line in %s!!\n", __LINE__, __FILE__); // TODO: is this ever called? if yes check for errors for(i = 0; i < k; ++i) periodization_buf[(N_p - k) + i] = input[i % N]; for(i = 1; i < (N_p - k); ++i) periodization_buf[(N_p - k) - i] = input[N - (i%N)]; //for(i = 0; i < N_p; ++i) // printf("%f ", periodization_buf[i]); //printf("--\n"); //for(i = 0; i < N_p; ++i) // printf("%f ", periodization_buf_rear[i]); //printf("\n"); } ptr_base = periodization_buf + F_2 - 1; if(k%2 == 1){ sum_odd = 0; for(j = 0; j < F_2; ++j) sum_odd += filter_odd[j] * ptr_base[-j]; *(ptr_out++) += sum_odd; --k; if(k) upsampling_convolution_valid_sf(periodization_buf + 1, N_p-1, filter, F, ptr_out, O-1, MODE_ZEROPAD); ptr_out += k; // k0 - 1 // really move backward by 1 } else if(k){ upsampling_convolution_valid_sf(periodization_buf, N_p, filter, F, ptr_out, O, MODE_ZEROPAD); ptr_out += k; } } } // MODE_PERIODIZATION /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // perform _valid_ convolution (only when all filter_even and filter_odd elements are in range of input data) // this part is quite simple, no extra hacks ptr_base = (DTYPE*)input + F_2 - 1; for(i = 0; i < N-(F_2-1); ++i){ // sliding over signal from left to right sum_even = 0; sum_odd = 0; // iterate filters elements for(j = 0; j < F_2; ++j){ sum_even += filter_even[j] * ptr_base[i-j]; sum_odd += filter_odd[j] * ptr_base[i-j]; } *(ptr_out++) += sum_even; *(ptr_out++) += sum_odd; } // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // MODE_PERIODIZATION if(mode == MODE_PERIODIZATION){ if(N_p>0){ k = F_2-1; if(k%2 == 1){ if(F/2 <= N_p - 1) // k > 1 ? upsampling_convolution_valid_sf(periodization_buf_rear , N_p-1, filter, F, ptr_out, O-1, MODE_ZEROPAD); ptr_out += k; // move forward anyway -> see lower if(F_2%2 == 0){ // remaining one element ptr_base = periodization_buf_rear + N_p - 1; sum_even = 0; for(j = 0; j < F_2; ++j) sum_even += filter_even[j] * ptr_base[-j]; *(--ptr_out) += sum_even; // move backward first } } else { if(k) upsampling_convolution_valid_sf(periodization_buf_rear, N_p, filter, F, ptr_out, O, MODE_ZEROPAD); } } if(periodization_buf != NULL) wtfree(periodization_buf); if(periodization_buf_rear != NULL) wtfree(periodization_buf_rear); } // MODE_PERIODIZATION /////////////////////////////////////////////////////////////////////////// wtfree(filter_even); wtfree(filter_odd); return 0; }