2017-03-23 41 views
2

FFTW를 사용하여 실수로 2 차원 푸리에 변환을 수행하려고합니다. 내 데이터는 동적 크기의 고유 매트릭스에 저장됩니다.Eigen 및 FFTW를 사용한 2D 푸리에 변환

FFT2D.h :

#include <Eigen> 

class FFT2D { 
public: 

    enum FFT_TYPE {FORWARD=0, REVERSE=1}; 
    FFT2D(EMatrix &input, EMatrix &output, FFT_TYPE type_ = FORWARD); 
    ~FFT2D(); 

    void execute(); 

private: 
    EMatrix& input; 
    EMatrix& output; 
    fftw_plan plan; 
    FFT_TYPE type; 
}; 

FFT2D.cpp :

#include "FFT2D.h" 
#include <fftw3.h> 
#include "Defs.h" 


FFT2D::FFT2D(EMatrix &input_, EMatrix &output_, FFT_TYPE type_) 
     : type(type_), input(input_), output(output_) { 

    if (type == FORWARD) 
     plan = fftw_plan_dft_2d((int) input.rows(), (int) input.cols(), 
       (fftw_complex *) &input(0), (fftw_complex *) &output(0), 
       FFTW_FORWARD, FFTW_ESTIMATE); 
    else 
     // placeholder for ifft-2d code, unwritten 
} 


FFT2D::~FFT2D() { 
    fftw_destroy_plan(plan); 
} 

void FFT2D::execute() { 
    fftw_execute(plan); // seg-fault here 
} 

그리고 EMatrix에 대한 정의가 : 여기에 내가 쓴 래퍼 클래스의

typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> EMatrix; 

문제는, FFT2D::execute()에 seg 오류가 발생합니다. 저는 생성자에서 뭔가 잘못된 것을 설정하고 있다는 것을 알고 있습니다. 여러 가지 방법을 시도했지만, 이것에 대해서는 어떤 진전을 이루지 못하고 있습니다. 내가 해봤

상황은 다음과 같습니다, Eigen::ColMajorEMatrix 타입 정의를 변경 fftw_plan_dft_2d(fftw_complex *) input.data()를 통과, 다른 FFTW 계획 (fftw_plan_dft_r2c_2d)를 사용.

내 C++는 (분명히) 녹슨이지만, 하루의 끝에 내가 필요한 것은 두 배의 실수 2D 아이겐 매트릭스에 2D FT을하는 것입니다. 미리 감사드립니다.

답변

0

여기서 중요한 문제는 "실수 값 푸리에 변환"과 같은 것이 없다는 것입니다. 그것은 단지 푸리에 제로 허수 부분에 뭔가 변화,하지만 제로는 여전히 fftw_complex 정의에서 볼 수 있듯이, 거기에 있습니다

typedef double fftw_complex[2];

이 출력으로 의미가 할 수있는 (그리고 아마도 것입니다) 허위 부분이 0이 아니다.
출력에는 몇 가지 대칭 속성이 있지만, 즉 1D 변환의 경우에는 짝수 함수가됩니다.

결과적으로 (fftw_complex *) &input(0) 캐스트가 제대로 작동하지 않습니다. FFTW는 전달할 때 두 배의 값을 가지 려합니다 (double).

이 솔루션은 제로로 매트릭스 원시 데이터를 인터리브하는 것이며,이를위한 여러 가지 방법이있다. 몇 가지 예 :

  • 전체 배열을 FFTW로 전달하기 전에 새 배열로 복사하여 처리 중에 0을 추가 할 수 있습니다.
  • 매트릭스 자체에 0을위한 공간을 확보 할 수 있습니다. 이렇게하면 복사를 피할 수 있지만, 리팩토링이 많이 필요할 것입니다. :)
  • 가장 좋은 방법은 사용하는 것입니다. std::complex<double>을 스칼라로 사용하십시오. 이것은 다소 "실제 가치가있는 FFT"에 대한 통지를 해칠 것이지만, 처음에는 그런 것이 거의 없습니다. 대신 모든 실제 가치 조작을 그대로 유지할 수 있으며 std::complex의 레이아웃은 fftw_complex에 완벽하게 맞습니다.

에 OK 보인다 저장하기 위해 같은 여기서 고려해야 할 몇 가지 다른 것들 (FFTW 행 주요 순서로 배열에서 작동하므로 아이겐 행렬을 준수해야합니다)와 아이겐 매트릭스 데이터에 대한 선형 액세스 (의 유효성가있을 수 있습니다 나를).

+0

유익한 게시물 주셔서 감사합니다.제 언어가 엉망이었을 거라 생각했는데, FFT에 대한 입력은 "실수"였습니다. 즉, 당신이 말한 것처럼 허수 부분에 모두 제로를 가졌습니다. 내 후속 질문은 세 번째 글 머리 부분에 관한 것입니다 : "std :: complex "을 스칼라로 사용하면 무엇을 의미합니까? 위와 같이 사용하고있는'EMatrix' typedef에 이것을 놓을 수 있습니까? –

+0

@halp_me 네, typedef에서'double'을'std :: complex '으로 바꿀 수 있습니다. 그러나 이미 인터리브 0이있는 경우이 방법으로 유지하는 것이 더 간단 할 것입니다. 내가 상상의 한 부분이 없다고 생각한 이유는'input.rows()'와'input.cols()'를 FFTW에 전달했기 때문입니다. 실제로이 중 하나를 2로 나누고 싶다고 확신합니다. – Ap31