I am trying to print out a 3D matrix into a text file that can be read by a MATLAB code. The example I have here prints the tensor in a text file but when I try to open it in MATLAB it reads something like 256 x 16 instead of 16x16x16.
Example:
static const int nx = 16;
static const int ny = 16;
static const int nz = 16;double Lx = 128;
double Ly = 128;
double LZ = 128;
double dx = Lx / nx;
double dy = Ly / ny;
double dz = Lz / nz;
double a = (2 * EIGEN_PI)/Lx;
double b = (2 * EIGEN_PI)/ Ly;
Eigen::Tensor<double, 3> X(nx,ny,nz);
eXX.setZero();
Eigen::Tensor<double, 3> Y(nx,ny,nz);
eYY.setZero();
Eigen::Tensor<double, 3> Z(nx,ny,nz);
eZZ.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
X(k,i,j) = i*dx;
Y(j,i,k) = j*dy;
Z(j,i,k) = k*dz;
}
}
}
Eigen::Tensor<double, 3> Out(nx,ny,nz);
Out.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
Out(k,i,j) = sin(3. * a * Z(k,i,j)) * sin(a * X(k,i,j)) * cos(b * Y(k,i,j));
}
}
}
std::ofstream file("test.txt");
if (file.is_open())
{
file << Out << '\n';
}
I know I will probably have to write my own output routine instead os using the operator << since it treats a rank-3 tensor as a 2-d matrix for the purpose of output.
Related
I am fairly new with Eigen and I read about Eigen unsupported tensor, which I decided to give it a try. I am trying to copy the output of an array after taking the 3D FFT to a complex Eigen tensor and I am not sure how to do it correctly. Is this feature available for Eigen Tensor?
A simple working example:
static const int nx = 4;
static const int ny = 4;
static const int nz = 4;
double Lx = 2*EIGEN_PI;
double Ly = 2*EIGEN_PI;
double dx = Lx / nx;
double dy = Ly / ny;
Eigen::Tensor<double, 3> eXX(nx,ny,nz);
eXX.setZero();
Eigen::Tensor<double, 3> eYY(nx,ny,nz);
eYY.setZero();
Eigen::Tensor<double, 3> eZZ(nx,ny,nz);
eZZ.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
eXX(k,i,j) = i*dx;
eYY(j,i,k) = j*dy;
eZZ(j,i,k) = k*dz;
}
}
}
double A = (2 * EIGEN_PI)/Lx;
double B= (2 * EIGEN_PI)/ Ly;
Eigen::Tensor<double, 3> Fun(nx,ny,nz);
Fun.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
Fun(k,i,j) = pow(eZZ(k,i,j),2.0) * sin(A * eXX(k,i,j)) * sin(B * eYY(k,i,j));
}
}
}
#define IMAG 1
#define REAL 0
fftw_complex *input_array;
fftw_complex *output_array;
input_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
output_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
for (int k = 0; k < nz; ++k) {
{
input_array[k + nz * (j + ny * i)][REAL] = Fun(k,i,j);
input_array[k + nz * (j + ny * i)][IMAG] = 0;
}
}
}
}
fftw_plan forward = fftw_plan_dft_3d(nx, ny, nz, input_array, output_array, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(forward);
fftw_destroy_plan(forward);
fftw_cleanup();
I am trying to copy the output to a tensor with the definition:
Eigen::Tensor<std::complex<double>, 3> Test(nx,ny,nz);
Test.setZero();
My attempt:
Eigen::Tensor<double, 3> Re(nx,ny,nz);
Re.setZero();
Eigen::Tensor<std::complex<double>, 3> Im(nx,ny,nz);
Im.setZero();
for(int i=0; i < nx; ++i){
for(int j=0; j < ny; ++j) {
for(int k=0; k < nz; ++k) {
Re(k,i,j) = output_array[k + nz * (j + ny * i)][REAL];
Im(k,i,j) = output_array[k + nz * (j + ny * i)][IMAG];
}
}
}
Test.real() = Re;
Test.imag() = Im;
Unfortunately, this above attempt is not working. I get the error:
error: use of deleted function ‘Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >& Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >::operator=(Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >&&)’
370 | Test.imag() = Im;
error: non-static reference member ‘const Eigen::Tensor<std::complex<double>, 3>& Eigen::TensorCwiseUnaryOp<Eigen::internal::scalar_imag_op<std::complex<double> >, const Eigen::Tensor<std::complex<double>, 3> >::m_xpr’, can’t use default assignment operator
No you can't assign the real or imaginary part of a Tensor using the real() or imag() operation. The unsupported Tensor interface does not perfectly match with the core Matrix or Array interface.(Unsupported modules are contribution from third party developers, not core developers.)
You can see the difference in the following sources, scrapped from the 3.4.0 version.
This is the implementation of the Matrix at Eigen/src/plugins/CommonCwiseUnaryOps.h.
typedef CwiseUnaryView<internal::scalar_imag_ref_op<Scalar>, Derived> NonConstImagReturnType;
...
NonConstImagReturnType
imag() { return NonConstImagReturnType(derived()); }
This is the implementation of Tensor at unsupported/Eigen/CXX11/src/Tensor/TensorBase.h.
... const TensorCwiseUnaryOp<internal::scalar_imag_op<Scalar>, const Derived>
imag() const { return unaryExpr(internal::scalar_imag_op<Scalar>()); }
I am trying to turn the following code to a function:
Update: added full working example to test and run. Thanks.
static const int nx = 4;
static const int ny = 4;
static const int nz = 4;
double Lx = 2*EIGEN_PI;
double Ly = 2*EIGEN_PI;
double A = (2 * EIGEN_PI)/Lx;
double A1 = (2 * EIGEN_PI)/ Ly;
Eigen::Tensor<double, 3> eXX(nx,ny,nz);
eXX.setZero();
Eigen::Tensor<double, 3> eYY(nx,ny,nz);
eYY.setZero();
Eigen::Tensor<double, 3> eZZ(nx,ny,nz);
eZZ.setZero();
double dx = Lx / nx;
double dy = Ly / ny;
double dz = Lz / nz;
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
eXX(k,i,j) = i*dx;
eYY(j,i,k) = j*dy;
eZZ(j,i,k) = k*dz;
}
}
}
Eigen::Tensor<double, 3> uFun(nx,ny,nz);
uFun.setZero();
for(int i = 0; i< nx; i++){
for(int j = 0; j< ny; j++){
for(int k = 0; k< nz; k++){
uFun(k,i,j) = sin(3. * A * eZZ(k,i,j)) * sin(A * eXX(k,i,j)) * cos(A1 * eYY(k,i,j));
}
}
}
//Turn this to function
#define IMAG 1
#define REAL 0
fftw_complex *input_array;
fftw_complex *output_array;
input_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
output_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
for (int k = 0; k < nz; ++k) {
{
input_array[k + nz * (j + ny * i)][REAL] = uFun(k,i,j);
input_array[k + nz * (j + ny * i)][IMAG] = 0;
}
}
}
}
fftw_plan forward = fftw_plan_dft_3d(nx, ny, nz, input_array, output_array, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(forward);
fftw_destroy_plan(forward);
fftw_cleanup();
My attempt:
void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr){
fftw_complex *input_array;
fftw_complex *output_array;
input_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
output_array = (fftw_complex*) fftw_malloc(nx*ny*nz * sizeof(fftw_complex));
for (int i = 0; i < nx; ++i) {
for (int j = 0; j < ny; ++j) {
for (int k = 0; k < nz; ++k) {
{
input_array[k + nz * (j + ny * i)][REAL] = rArr(k,i,j);
input_array[k + nz * (j + ny * i)][IMAG] = 0;
}
}
}
}
//this is correct 3D fft of uFun = fftn(uFun) in MATLAB
fftw_plan forward = fftw_plan_dft_3d(nx, ny, nz, input_array, output_array, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(forward);
fftw_destroy_plan(forward);
fftw_cleanup();
}
But I get all these errors:
error: variable or field ‘r2cfft3d’ declared void
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
| ^~~~~~
spectralFunctions3D.h:27:22: error: ‘Tensor’ is not a member of ‘Eigen’
spectralFunctions3D.h:27:29: error: expected primary-expression before ‘double’
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
error: ‘rArr’ was not declared in this scope
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
error: ‘cArr’ was not declared in this scope
27 | void r2cfft3d(Eigen::Tensor<double, 3>& rArr, Eigen::Tensor<std::complex<double>, 3> cArr);
| ^~~~
I don't understand these errors, espically that the code works fine before trying to turn it into a function. I am more familiar with passing Eigen matrices to function but not Eigen tensors. Thanks
I managed to compile this fine by including all the relevant headers (especially #include <unsupported/Eigen/CXX11/Tensor>).
Since you are using const sizes for the Eigen Tensors you could define them as fixed size with
Eigen::TensorFixedSize<double, Eigen::Sizes<nx, ny, nz>>
Also take a look at this: https://www.fftw.org/fftw3_doc/Column_002dmajor-Format.html , maybe you can avoid the conversion from column-major to row-major and pass directly the pointer to the Eigen Tensor.
I am trying to calculate the partial derivative of the function Sin(x)Sin(y) along the x-direction using Fourier Transform (FFTW library in C++). I take my function from real to Fourier space (fftw_plan_dft_r2c_2d), multiply the result by -i * kappa array (wavenumber/spatial frequency), and then transform the result back into real space (fftw_plan_dft_c2r_2d). Finally, I divide the result by the size of my 2D array Nx*Ny (I need to do this based on the documentation). However, the resulting function is scaled up by some value and the amplitude is not 1.
'''
#define Nx 360
#define Ny 360
#define REAL 0
#define IMAG 1
#define Pi 3.14
#include <stdio.h>
#include <math.h>
#include <fftw3.h>
#include <iostream>
#include <iostream>
#include <fstream>
#include <iomanip>
int main() {
int i, j;
int Nyh = Ny / 2 + 1;
double k1;
double k2;
double *signal;
double *result2;
double *kappa1;
double *kappa2;
double df;
fftw_complex *result1;
fftw_complex *dfhat;
signal = (double*)fftw_malloc(sizeof(double) * Nx * Ny );
result2 = (double*)fftw_malloc(sizeof(double) * Nx * Ny );
kappa1 = (double*)fftw_malloc(sizeof(double) * Nx * Nyh );
result1 = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Nx * Nyh);
dfhat = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Nx * Nyh);
for (int i = 0; i < Nx; i++){
if ( i < Nx/2 + 1)
k1 = 2 * Pi * (-Nx + i) / Nx;
else
k1 = 2 * Pi * i / Nx;
for (int j = 0; j < Nyh; j++){
kappa1[j + Nyh * i] = k1;
}
}
fftw_plan plan1 = fftw_plan_dft_r2c_2d(Nx,Ny,signal,result1,FFTW_ESTIMATE);
fftw_plan plan2 = fftw_plan_dft_c2r_2d(Nx,Ny,dfhat,result2,FFTW_ESTIMATE);
for (int i=0; i < Nx; i++){
for (int j=0; j < Ny; j++){
double x = (double)i / 180 * (double) Pi;
double y = (double)j / 180 * (double) Pi;
signal[j + Ny * i] = sin(x) * sin(y);
}
}
fftw_execute(plan1);
for (int i = 0; i < Nx; i++) {
for (int j = 0; j < Nyh; j++) {
dfhat[j + Nyh * i][REAL] = 0;
dfhat[j + Nyh * i][IMAG] = 0;
dfhat[j + Nyh * i][IMAG] = -result1[j + Nyh * i][REAL] * kappa1[j + Nyh * i];
dfhat[j + Nyh * i][REAL] = result1[j + Nyh * i][IMAG] * kappa1[j + Nyh * i];
}
}
fftw_execute(plan2);
for (int i = 0; i < Nx; i++) {
for (int j = 0; j < Ny; j++) {
result2[j + Ny * i] /= (Nx*Ny);
}
}
for (int j = 0; j < Ny; j++) {
for (int i = 0; i < Nx; i++) {
std::cout <<std::setw(15)<< result2[j + Ny * i];
}
std::cout << std::endl;
}
fftw_destroy_plan(plan1);
fftw_destroy_plan(plan2);
fftw_free(result1);
fftw_free(dfhat);
return 0;
}
'''
This is how the result looks
I have defined my kappa array to have Nx * Ny/2+1 elements and have split the array at the center (as all references suggest). But it does not work. I would appreciate any help!
I am attempting to write a naive implementation of the Short-Time Fourier Transform using consecutive FFT frames in time, calculated using the FFTW library, but I am getting a Segmentation fault and cannot work out why.
My code is as below:
// load in audio
AudioFile<double> audioFile;
audioFile.load ("assets/example-audio/file_example_WAV_1MG.wav");
int N = audioFile.getNumSamplesPerChannel();
// make stereo audio mono
double fileDataMono[N];
if (audioFile.isStereo())
for (int i = 0; i < N; i++)
fileDataMono[i] = ( audioFile.samples[0][i] + audioFile.samples[1][i] ) / 2;
// setup stft
// (test transform, presently unoptimized)
int stepSize = 512;
int M = 2048; // fft size
int noOfFrames = (N-(M-stepSize))/stepSize;
// create Hamming window vector
double w[M];
for (int m = 0; m < M; m++) {
w[m] = 0.53836 - 0.46164 * cos( 2*M_PI*m / M );
}
double* input;
// (pads input array if necessary)
if ( (N-(M-stepSize))%stepSize != 0) {
noOfFrames += 1;
int amountOfZeroPadding = stepSize - (N-(M-stepSize))%stepSize;
double ipt[N + amountOfZeroPadding];
for (int i = 0; i < N; i++) // copy values from fileDataMono into input
ipt[i] = fileDataMono[i];
for (int i = 0; i < amountOfZeroPadding; i++)
ipt[N + i] = 0;
input = ipt;
} else {
input = fileDataMono;
}
// compute stft
fftw_complex* stft[noOfFrames];
double frames[noOfFrames][M];
fftw_plan fftPlan;
for (int i = 0; i < noOfFrames; i++) {
stft[i] = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * M);
for (int m = 0; m < M; m++)
frames[i][m] = input[i*stepSize + m] * w[m];
fftPlan = fftw_plan_dft_r2c_1d(M, frames[i], stft[i], FFTW_ESTIMATE);
fftw_execute(fftPlan);
}
// compute istft
double* outputFrames[noOfFrames];
double output[N];
for (int i = 0; i < noOfFrames; i++) {
outputFrames[i] = (double*)fftw_malloc(sizeof(double) * M);
fftPlan = fftw_plan_dft_c2r_1d(M, stft[i], outputFrames[i], FFTW_ESTIMATE);
fftw_execute(fftPlan);
for (int m = 0; i < M; m++) {
output[i*stepSize + m] += outputFrames[i][m];
}
}
fftw_destroy_plan(fftPlan);
for (int i = 0; i < noOfFrames; i++) {
fftw_free(stft[i]);
fftw_free(outputFrames[i]);
}
// output audio
AudioFile<double>::AudioBuffer outputBuffer;
outputBuffer.resize (1);
outputBuffer[0].resize(N);
outputBuffer[0].assign(output, output+N);
bool ok = audioFile.setAudioBuffer(outputBuffer);
audioFile.setAudioBufferSize (1, N);
audioFile.setBitDepth (16);
audioFile.setSampleRate (8000);
audioFile.save ("out/audioOutput.wav");
The segfault seems to be being raised by the first fftw_malloc when computing the forward STFT.
Thanks in advance!
The relevant bit of code is:
double* input;
if ( (N-(M-stepSize))%stepSize != 0) {
double ipt[N + amountOfZeroPadding];
//...
input = ipt;
}
//...
input[i*stepSize + m];
Your input pointer points at memory that exists only inside the if statement. The closing brace denotes the end of the lifetime of the ipt array. When dereferencing the pointer later, you are addressing memory that no longer exists.
I am trying to FFT an image using the library from http://www.fftw.org/. basically i want to do a forward transform and then the backward transform to get the input image i have chosen. Then I would like to get my input back with the backward FFT, but it doesn't work. Here is my code :
double n[w][h][2];
double im[w][h][2];
const int Lx = w;
const int Lt = h;
int var_x;
int var_t;
fftw_complex *in, *out, *result;
fftw_plan p;
fftw_plan inv_p;
in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
result = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *Lx *Lt);
p = fftw_plan_dft_2d(Lx, Lt, in, out, FFTW_FORWARD, FFTW_MEASURE);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
in[t + Lt*x][0] = n[x][t][0];
in[t + Lt*x][1] = 0;
}
}
fftw_execute(p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
n[x][t][0] = out[t + Lt*x][0];
n[x][t][1] = out[t + Lt*x][1];
}
}
inv_p = fftw_plan_dft_2d(Lx, Lt, out, result, FFTW_BACKWARD, FFTW_MEASURE);
fftw_execute(inv_p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
im[x][t][0] = result[t + Lt*x][0];
im[x][t][1] = result[t + Lt*x][1];
std::cout<<im[x][t][0]<<std::endl;
}
}
fftw_destroy_plan(p);
fftw_free(in);
fftw_free(out);
As you can see, I just try to perform a normal FFT, then to reverse it. The problem is that my output 'im' is just full of 0, instead of 1 and 0...
So what's wrong with my code ?
Thank you :)
Your original image and transform matrices are declared as int. Try defining them as double:
double n[w][h][2];
double im[w][h][2];
The line below, for example, is destroying data because result[i][j] is of type double (as of fftw_complex definition). So that if result[i][j] == 0.99, it'll be converted to 0.
im[x][t][0] = result[t + Lt*x][0]; //A value of 0.99 may be converted to 0
This is the corrected version of the code which is now working - thank you to everybody who helped me to fix all the problems.
double n[w][h][2];
double im[w][h][2];
const int Lx = w;
const int Lt = h;
int var_x;
int var_t;
fftw_complex *in, *out, *result;
fftw_plan p;
fftw_plan inv_p;
in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Lx*Lt);
result = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) *Lx *Lt);
p = fftw_plan_dft_2d(Lx, Lt, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
in[t + Lt*x][0] = n[x][t][0];
in[t + Lt*x][1] = 0;
}
}
fftw_execute(p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
n[x][t][0] = out[t + Lt*x][0];
n[x][t][1] = out[t + Lt*x][1];
}
}
inv_p = fftw_plan_dft_2d(Lx, Lt, out, result, FFTW_BACKWARD, FFTW_ESTIMATE);
fftw_execute(inv_p);
for (int x = 0; x < Lx; x++)
{
for (int t = 0; t < Lt; t++)
{
im[x][t][0] = result[t + Lt*x][0];
im[x][t][1] = result[t + Lt*x][1];
std::cout<<im[x][t][0]<<std::endl;
}
}
fftw_destroy_plan(p);
fftw_destroy_plan(inv_p);
fftw_free(in);
fftw_free(out);
fftw_free(result);