使用 fftw 在 C 中生成粉红噪声图像
generating pink noise images in C with fftw
我正在尝试使用 FFTW 在 C 中生成二维粉红噪声 (1/f) 图像
fftw_complex * Xf = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nrows*ncolumns);
fftw_plan ift = fftw_plan_dft_c2r_2d(nrows,ncolumns,Xf,image,FFTW_BACKWARD|FFTW_ESTIMATE);
for (int rr=0; rr<nrows; rr++) {
for (int cc=0; cc<ncolumns; cc++) {
if (rr<=nrows/2) {
u = 1.0*rr/nrows;
}
else {
u = 1.0*(rr-nrows)/nrows;
}
if (cc<=ncolumns/2) {
v = 1.0*cc/ncolumns;
}
else {
v = 1.0*(cc-ncolumns)/ncolumns;
}
// 1/f power spectrum
w = pow(u,2)+pow(v,2);
if (w!=0) {
Sf = pow(w,-1/2);
}
else {
Sf = 0;
}
// random phase
phi = 1.0*rand()/RAND_MAX;
// complex spectrum
Xf[rr+nrows*cc][0] = sqrt(Sf) * cos(2*pi*phi);
Xf[rr+nrows*cc][1] = sqrt(Sf) * sin(2*pi*phi);
}
}
fftw_execute(ift);
当我在 matlab 中使用相同的频谱 (real(ifft2(...)) 进行傅立叶逆变换时,我得到了一个典型的粉红噪声图像(左下方)。但是 FFTW 返回的图像是不是粉红噪音(右):example of pink noise images。
如果我尝试发出棕色噪声 (1/f2),我会得到更糟的结果:example and brown noise images。
有人知道为什么我没有从 FFTW 傅立叶逆变换中得到正确的图像吗?我在 matlab 中得到的图像是正确的,所以光谱似乎不是问题。
复杂数组 Xf
对于 c2r 转换来说太大了。大小为 n0*n1
的实数数组的 r2c 变换是大小为 n0*(n1/2+1)
的复数数组(参见 fftw Real-data DFT Array Format. It makes sense due to a particular property of the DFT transform。实际上,如果 X
是长度为 n
,它的DFT变换Xf的辅数Xf[n-k]
是Xf[k]
的复共轭。因此,通过去掉一半的复数数组可以节省时间和内存。
通过调用 fftw_plan ift = fftw_plan_dft_c2r_2d(nrows,ncolumns,Xf,image,FFTW_BACKWARD|FFTW_ESTIMATE);
fftw 创建一个计划,将 nrows*(ncolumns/2+1)
复数数组 Xf
转换回 nrow*ncolumn
实数数组。因此,要相应地计算频率。
以下示例代码基于您的示例代码生成可以使用 paraview 计算的 VTK 图像。它由 gcc main.c -o main -lfftw3 -lm -Wall
编译
#include<stdlib.h>
#include<complex.h>
#include<math.h>
#include<fftw3.h>
#define PI 3.14159265358979323846
int main(void){
int nrows=400;
int ncolumns=1000;
double* image=malloc(nrows*ncolumns*sizeof(double));
fftw_complex * Xf = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nrows*(ncolumns/2+1));
fftw_plan ift = fftw_plan_dft_c2r_2d(nrows,ncolumns,Xf,image,FFTW_BACKWARD|FFTW_ESTIMATE);
int rr;
int cc;
double u,v,w,phi,Sf;
for (rr=0; rr<nrows; rr++) {
for (cc=0; cc<ncolumns/2+1; cc++) {
if (rr<=nrows/2) {
u = 1.0*rr/nrows;
}
else {
u = 1.0*(rr-nrows)/nrows;
}
v = 1.0*cc/ncolumns;
// 1/f power spectrum
w = pow(u,2)+pow(v,2);
if (w!=0) {
// Sf = pow(w,-1./2);
Sf = pow(w,-1.);
}
else {
Sf = 0;
}
// random phase
phi = 1.0*rand()/RAND_MAX;
// complex spectrum
//Xf[rr*(ncolumns/2+1)+cc][0] = sqrt(Sf) * cos(2*pi*phi);
//Xf[rr*(ncolumns/2+1)+cc][1] = sqrt(Sf) * sin(2*pi*phi);
Xf[rr*(ncolumns/2+1)+cc]=sqrt(Sf)*(cos(2*PI*phi)+I*sin(2*PI*phi));
}
}
fftw_execute(ift);
// writing to VTK file
FILE* file=fopen("image.vtk","w");
fprintf(file,"# vtk DataFile Version 2.0\n");
fprintf(file,"pinknoise\n");
fprintf(file,"ASCII\n");
fprintf(file,"DATASET STRUCTURED_POINTS\n");
fprintf(file,"DIMENSIONS %d %d 1\n",nrows,ncolumns);
fprintf(file,"ASPECT_RATIO 1 1 1\n");
fprintf(file,"ORIGIN 0 0 0\n");
fprintf(file,"POINT_DATA %d\n",nrows*ncolumns);
fprintf(file,"SCALARS image double 1\n");
fprintf(file,"LOOKUP_TABLE default\n");
for (cc=0; cc<ncolumns; cc++) {
for (rr=0; rr<nrows; rr++) {
fprintf(file,"%lf ",image[rr*(ncolumns)+cc]);
}
}
fclose(file);
fftw_destroy_plan(ift);
fftw_free(Xf);
free(image);
return(0);
}
我正在尝试使用 FFTW 在 C 中生成二维粉红噪声 (1/f) 图像
fftw_complex * Xf = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nrows*ncolumns);
fftw_plan ift = fftw_plan_dft_c2r_2d(nrows,ncolumns,Xf,image,FFTW_BACKWARD|FFTW_ESTIMATE);
for (int rr=0; rr<nrows; rr++) {
for (int cc=0; cc<ncolumns; cc++) {
if (rr<=nrows/2) {
u = 1.0*rr/nrows;
}
else {
u = 1.0*(rr-nrows)/nrows;
}
if (cc<=ncolumns/2) {
v = 1.0*cc/ncolumns;
}
else {
v = 1.0*(cc-ncolumns)/ncolumns;
}
// 1/f power spectrum
w = pow(u,2)+pow(v,2);
if (w!=0) {
Sf = pow(w,-1/2);
}
else {
Sf = 0;
}
// random phase
phi = 1.0*rand()/RAND_MAX;
// complex spectrum
Xf[rr+nrows*cc][0] = sqrt(Sf) * cos(2*pi*phi);
Xf[rr+nrows*cc][1] = sqrt(Sf) * sin(2*pi*phi);
}
}
fftw_execute(ift);
当我在 matlab 中使用相同的频谱 (real(ifft2(...)) 进行傅立叶逆变换时,我得到了一个典型的粉红噪声图像(左下方)。但是 FFTW 返回的图像是不是粉红噪音(右):example of pink noise images。 如果我尝试发出棕色噪声 (1/f2),我会得到更糟的结果:example and brown noise images。 有人知道为什么我没有从 FFTW 傅立叶逆变换中得到正确的图像吗?我在 matlab 中得到的图像是正确的,所以光谱似乎不是问题。
复杂数组 Xf
对于 c2r 转换来说太大了。大小为 n0*n1
的实数数组的 r2c 变换是大小为 n0*(n1/2+1)
的复数数组(参见 fftw Real-data DFT Array Format. It makes sense due to a particular property of the DFT transform。实际上,如果 X
是长度为 n
,它的DFT变换Xf的辅数Xf[n-k]
是Xf[k]
的复共轭。因此,通过去掉一半的复数数组可以节省时间和内存。
通过调用 fftw_plan ift = fftw_plan_dft_c2r_2d(nrows,ncolumns,Xf,image,FFTW_BACKWARD|FFTW_ESTIMATE);
fftw 创建一个计划,将 nrows*(ncolumns/2+1)
复数数组 Xf
转换回 nrow*ncolumn
实数数组。因此,要相应地计算频率。
以下示例代码基于您的示例代码生成可以使用 paraview 计算的 VTK 图像。它由 gcc main.c -o main -lfftw3 -lm -Wall
#include<stdlib.h>
#include<complex.h>
#include<math.h>
#include<fftw3.h>
#define PI 3.14159265358979323846
int main(void){
int nrows=400;
int ncolumns=1000;
double* image=malloc(nrows*ncolumns*sizeof(double));
fftw_complex * Xf = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nrows*(ncolumns/2+1));
fftw_plan ift = fftw_plan_dft_c2r_2d(nrows,ncolumns,Xf,image,FFTW_BACKWARD|FFTW_ESTIMATE);
int rr;
int cc;
double u,v,w,phi,Sf;
for (rr=0; rr<nrows; rr++) {
for (cc=0; cc<ncolumns/2+1; cc++) {
if (rr<=nrows/2) {
u = 1.0*rr/nrows;
}
else {
u = 1.0*(rr-nrows)/nrows;
}
v = 1.0*cc/ncolumns;
// 1/f power spectrum
w = pow(u,2)+pow(v,2);
if (w!=0) {
// Sf = pow(w,-1./2);
Sf = pow(w,-1.);
}
else {
Sf = 0;
}
// random phase
phi = 1.0*rand()/RAND_MAX;
// complex spectrum
//Xf[rr*(ncolumns/2+1)+cc][0] = sqrt(Sf) * cos(2*pi*phi);
//Xf[rr*(ncolumns/2+1)+cc][1] = sqrt(Sf) * sin(2*pi*phi);
Xf[rr*(ncolumns/2+1)+cc]=sqrt(Sf)*(cos(2*PI*phi)+I*sin(2*PI*phi));
}
}
fftw_execute(ift);
// writing to VTK file
FILE* file=fopen("image.vtk","w");
fprintf(file,"# vtk DataFile Version 2.0\n");
fprintf(file,"pinknoise\n");
fprintf(file,"ASCII\n");
fprintf(file,"DATASET STRUCTURED_POINTS\n");
fprintf(file,"DIMENSIONS %d %d 1\n",nrows,ncolumns);
fprintf(file,"ASPECT_RATIO 1 1 1\n");
fprintf(file,"ORIGIN 0 0 0\n");
fprintf(file,"POINT_DATA %d\n",nrows*ncolumns);
fprintf(file,"SCALARS image double 1\n");
fprintf(file,"LOOKUP_TABLE default\n");
for (cc=0; cc<ncolumns; cc++) {
for (rr=0; rr<nrows; rr++) {
fprintf(file,"%lf ",image[rr*(ncolumns)+cc]);
}
}
fclose(file);
fftw_destroy_plan(ift);
fftw_free(Xf);
free(image);
return(0);
}