/* * Invert a toeplitz matrix. Input is the first column of the matrix and also * is the output. * IMP - size must be a power of two. */ void serial_matrix_inversion(size_t size, const fftw_complex *input, fftw_complex *result) { if(size < 1) return; //base case result[0] = 1 / input[0]; if(size < 2) return; result[1] = - result[0] * input[1] * result[0]; unsigned int current_size = 2; while(current_size < size) { fftw_complex *reversed_input = alloc_reverse_from_vec(current_size * 2 - 1, input); fftw_complex *temporary = alloc_complex(current_size); //first convolution toeplitz_mult(current_size, reversed_input, result, temporary); fftw_complex *reversed_inverted_pad = alloc_complex(current_size * 2 - 1); zero_memory(current_size * 2 - 1, reversed_inverted_pad); memcpy(reversed_inverted_pad + (current_size-1), result, current_size * sizeof(fftw_complex)); reverse_vec(current_size * 2 - 1, reversed_inverted_pad); //second convolution reverse_vec(current_size, temporary); toeplitz_mult(current_size, reversed_inverted_pad, temporary, reversed_input); //complement sign for(int i=0; i < current_size; i++) reversed_input[i] = - reversed_input[i]; reverse_vec(current_size, reversed_input); //finally copy in result vec memcpy(result + current_size, reversed_input, current_size * sizeof(fftw_complex)); fftw_free(temporary); fftw_free(reversed_input); fftw_free(reversed_inverted_pad); current_size *= 2; } }
//' @title Discrete Wavelet Transform //' @description Calculation of the coefficients for the discrete wavelet transformation. //' @param x A \code{vector} with dimensions \eqn{N\times 1}{N x 1}. //' @param filter_name A \code{string} indicating the filter. //' @param nlevels An \code{integer}, \eqn{J}, indicating the level of the decomposition. //' @param boundary A \code{string} indicating the type of boundary method to use. Either \code{boundary="periodic"} or \code{"reflection"}. //' @param brickwall A \code{bool} indicating whether the a brick wall procedure should be applied to the coefficients. //' @return y A \code{field<vec>} that contains the wavelet coefficients for each decomposition level //' @details //' Performs a level J decomposition of the time series using the pyramid algorithm //' @author JJB //' @keywords internal //' @examples //' set.seed(999) //' x = rnorm(2^8) //' dwt_cpp(x, filter_name = "haar", nlevels = 4, boundary = "periodic", brickwall = TRUE) // [[Rcpp::export]] arma::field<arma::vec> dwt_cpp(arma::vec x, std::string filter_name, unsigned int nlevels, std::string boundary, bool brickwall) { if(boundary == "periodic"){ // }else if(boundary == "reflection"){ unsigned int temp_N = x.n_elem; arma::vec rev_vec = reverse_vec(x); x.resize(2*temp_N); x.rows(temp_N, 2*temp_N-1) = rev_vec; }else{ Rcpp::stop("The supplied 'boundary' argument is not supported! Choose either periodic or reflection."); } unsigned int N = x.n_elem; unsigned int J = nlevels; unsigned int tau = pow(2,J); if(double(N)/double(tau) != floor(double(N)/double(tau))){ Rcpp::stop("The supplied sample size ('x') must be divisible by 2^(nlevels). Either truncate or expand the number of samples."); } if(tau > N){ Rcpp::stop("The number of levels [ 2^(nlevels) ] exceeds sample size ('x'). Supply a lower number of levels."); } arma::field<arma::vec> filter_info = select_filter(filter_name); int L = arma::as_scalar(filter_info(0)); arma::vec h = filter_info(1); //check the pulls arma::vec g = filter_info(2); arma::field<arma::vec> y(J); for(unsigned int j = 1; j <= J; j++) { unsigned int M = N/pow(2,(j-1)); unsigned int M_over_2 = double(M)/2; arma::vec Wj(M_over_2); arma::vec Vj(M_over_2); for(unsigned t = 0; t < M_over_2; t++) { int u = 2*t + 1; double Wjt = h(0)*x(u); double Vjt = g(0)*x(u); for(int n = 1; n < L; n++){ u -= 1; if(u < 0){ u = M - 1; } Wjt += h(n)*x(u); Vjt += g(n)*x(u); } Wj[t] = Wjt; Vj[t] = Vjt; } y(j-1) = Wj; x = Vj; } // Apply brickwall if(brickwall){ y = brick_wall(y, filter_info, "dwt"); } return y; }
//' @title Maximum Overlap Discrete Wavelet Transform //' @description //' Calculation of the coefficients for the discrete wavelet transformation //' @inheritParams dwt_cpp //' @return y A \code{field<vec>} that contains the wavelet coefficients for each decomposition level //' @keywords internal //' @details //' Performs a level J decomposition of the time series using the pyramid algorithm. //' Use this implementation to supply custom parameters instead of modwt(x), //' which serves as a wrapper function. //' @author JJB //' @keywords internal //' @examples //' set.seed(999) //' x = rnorm(100) //' modwt_cpp(x, filter_name = "haar", nlevels = 4, boundary = "periodic", brickwall = TRUE) // [[Rcpp::export]] arma::field<arma::vec> modwt_cpp(arma::vec x, std::string filter_name, unsigned int nlevels, std::string boundary, bool brickwall){ if(boundary == "periodic"){ // }else if(boundary == "reflection"){ unsigned int temp_N = x.n_elem; arma::vec rev_vec = reverse_vec(x); x.resize(2*temp_N); x.rows(temp_N, 2*temp_N-1) = rev_vec; }else{ Rcpp::stop("The supplied 'boundary' argument is not supported! Choose either periodic or reflection."); } unsigned int N = x.n_elem; unsigned int J = nlevels; unsigned int tau = pow(2,J); if(tau > N) Rcpp::stop("The number of levels [ 2^(nlevels) ] exceeds sample size ('x'). Supply a lower number of levels."); arma::field<arma::vec> filter_info = select_filter(filter_name); int L = arma::as_scalar(filter_info(0)); arma::vec ht = filter_info(1); arma::vec gt = filter_info(2); // modwt transform double transform_factor = sqrt(2); ht /= transform_factor; gt /= transform_factor; arma::field<arma::vec> y(J); arma::vec Wj(N); arma::vec Vj(N); for(unsigned int j = 1; j <= J; j++) { for(unsigned t = 0; t < N; t++) { int k = t; double Wjt = ht(0)*x(k); double Vjt = gt(0)*x(k); for(int n = 1; n < L; n++){ k -= pow(2, j-1); if(k < 0){ k += N; } Wjt += ht(n)*x(k); Vjt += gt(n)*x(k); } Wj[t] = Wjt; Vj[t] = Vjt; } y(j-1) = Wj; x = Vj; } // Apply brickwall if(brickwall){ y = brick_wall(y, filter_info, "modwt"); } return y; }