需要帮助使本程序计算PSD

时间:2014-08-05 15:02:05

标签: c signal-processing fftw

我正在尝试制作一个计算时间系列PSD(16384样本)的程序,比如这里的窦是代码:

// generating sin samples 

#include <stdio.h>
#include <math.h>
#include <complex.h>

int main(){
    FILE *inp =NULL,*inp2;
    double value = 0.0; 
    float frequency = 1; // signal frequency 
    double timeSec = 1 ; // time in sec 
    unsigned int  numberOFSamples = 2048*8;
    double steps = timeSec / numberOFSamples; 
    double timer =0.0;
    float  dcValue =0.0;
    double index = 0;
     inp = fopen("sinus","wb+");
     inp2= fopen("sinusD","wb+");
    for( timer=0.0 ; timer<timeSec;timer+=steps){
        value= sin(2*M_PI*frequency*timer) +dcValue;
        fprintf(inp,"%lf ",value);
        fwrite(&value,sizeof(double),1,inp2);

     }

     fclose(inp);
     fclose(inp2);
     return 0;

}

生成的正弦值是正确的我现在用Matlab检查它到PSD应该是1024大这里是代码:

    #include <fftw3.h>
#include <math.h>
#include <stdio.h>
#include <complex.h>

#define WINDOW_SIZE 1024

int main (){
  FILE* inputFile = NULL;
  FILE* outputFile= NULL;
  double* inputData=NULL; 
  double* outputData=NULL;
  double* windowData=NULL;
  unsigned int windowSize = 1024;
  int overlaping =0;
  int index1 =0,index2=0, i=0;
  double powVal= 0.0;
  fftw_plan plan_r2hc;
  double w[WINDOW_SIZE];
  for (i=0; i<WINDOW_SIZE; i++) {
  w[i] = (1.0 - cos(2.0 * M_PI * i/(WINDOW_SIZE-1))) * 0.5;  // hann window
  }

// mememory allocation
  inputData = (double*) fftw_malloc(sizeof(double)*windowSize);
  outputData= (double*) fftw_malloc(sizeof(double)*windowSize);
  windowData= (double*) fftw_malloc(sizeof(double)*windowSize);
  plan_r2hc = fftw_plan_r2r_1d(windowSize, inputData, windowData, FFTW_R2HC, FFTW_PATIENT);
  // Opning files 
  inputFile = fopen("sinusD","rb");
  outputFile= fopen("windowingResult","wb+");
  if(inputFile==NULL ){
    printf("Couldn't open either the input or the output file \n");
    return -1;
  }

  while((i=fread(inputData,sizeof(double),windowSize,inputFile))==windowSize){   

    for( index1 =0; index1 < WINDOW_SIZE;index1++){
      inputData[index1]*=w[index1];
    //  printf("index %d \t %lf\n",index1,inputData[index1]);
    }
     fftw_execute_r2r(plan_r2hc, inputData, windowData);
     for( index1 =0; index1 < windowSize;index1++){
          outputData[index1]+=windowData[index1];
     }
     if(overlaping!=0)
      fseek(inputFile,(-overlaping)*sizeof(double),SEEK_CUR);
  }
  if( i!=0){
     i = -i;
    fseek(inputFile ,i*sizeof(double),SEEK_END);
    fread(inputData,sizeof(double),-i,inputFile);
    for( index1 =0; index1 < -i;index1++){
      inputData[index1]*=(1.0 - cos(2.0 * M_PI * index1/(windowSize-1)) * 0.5);
    //  printf("index %d \t %lf\n",index1,inputData[index1]);
    }
     fftw_execute_r2r(plan_r2hc, inputData, windowData);
     for( index1 =0; index1 < windowSize;index1++){
          outputData[index1]+=windowData[index1];
     }

  }


  powVal = outputData[0]*outputData[0];
  powVal /= (windowSize*windowSize)/2;
  index1 = 0;
  fprintf(outputFile,"%lf ",powVal);
  printf(" PSD \t %lf\n",powVal);
  for (index1 =1; index1<=windowSize;index1++){
            powVal = outputData[index1]*outputData[index1]+outputData[windowSize-index1]*outputData[windowSize- index1];
            powVal/=(windowSize*windowSize)/2;
          //  powVal = 20*log10(fabs(powVal));
            fprintf(outputFile,"%lf ",powVal);
            printf(" PsD %d \t %10.5lf\n",index1,powVal);
    }


  fftw_free(inputData);
  fftw_free(outputData);
  fftw_free(windowData);
  fclose(inputFile);
  fclose(outputFile);
}

我得到的结果只有0.0000为什么?我问过关于窗口和如何使用它的多个问题,但我真的不知道我在这里做错了什么,有什么想法吗?

2.更新 在SleuthEye的回答之后,结果看起来相当不错,比较结果和MATLAB的结果使用:

  [output,f] = pwelch(input,hann(8192));
    plot(output);

pwelch result

导入c程序的结果后,PSD是相同的,但规模不同:

Program result

正如您所看到的那样,规模并不相同。

2 个答案:

答案 0 :(得分:2)

正如chux所提到的,outputData数组的元素未初始化。

此外,使用Bartlett's method获得的功率谱密度估计应平均频谱值的功率(而不是计算平均功率):

outputData[index1] += windowData[index1]*windowData[index1];

最后,如果频谱缩放对您的应用很重要(即,如果您需要的频率成分的相对强度超过频率成分),那么您还应该将窗口效应考虑到您的归一化因子中,如{{3 }}:

double Wss = 0.0;
for (i=0; i<WINDOW_SIZE; i++) {
  Wss += w[i]*w[i];
}
Wss *= WINDOW_SIZE;

所以,将所有内容放在一起并考虑您正在使用的Numerical Recipes格式:

outputData = fftw_malloc(sizeof(double)*(windowSize/2 + 1));
for (index1 =0; index1 <= windowSize/2; index1++) {
  outputData[index1] = 0.0;
}
Wss = 0.0;
for (i=0; i<WINDOW_SIZE; i++) {
  Wss += w[i]*w[i];
}
Wss *= WINDOW_SIZE;
...

count = 0;
while((i=fread(inputData,sizeof(double),windowSize,inputFile))==windowSize) {   
  for( index1 =0; index1 < WINDOW_SIZE;index1++){
    inputData[index1]*=w[index1];
  }
  fftw_execute_r2r(plan_r2hc, inputData, windowData);

  outputData[0] += windowData[0]*windowData[0];
  for( index1 =1; index1 < windowSize/2;index1++)
  {
    double re = windowData[index1];
    double im = windowData[windowSize-index1];
    outputData[index1] += re*re + im*im;
  }
  outputData[windowSize/2] += windowData[windowSize/2]*windowData[windowSize/2];
  count++;
}
...
if (halfSpectrum){
  norm = count*Wss/2;
  powVal = outputData[0]/(2*norm);
  fprintf(outputFile,"%lf ",powVal);
  for (index1 =1; index1<windowSize/2;index1++){
    powVal = outputData[index1]/norm;
    fprintf(outputFile,"%lf ",powVal);
  }
  powVal = outputData[windowSize/2]/(2*norm);
  fprintf(outputFile,"%lf ",powVal);
}
else{
  norm = count*Wss;
  for (index1 =0; index1<=windowSize/2;index1++){
    powVal = outputData[index1]/norm;
    fprintf(outputFile,"%lf ",powVal);
  }
  for (index1 =windowSize/2-1; index1>0;index1--){
    powVal = outputData[index1]/norm;
    fprintf(outputFile,"%lf ",powVal);
  }
}

更新(与Matlab pwelch的差异说明):

根据Octave的pwelch帮助(应与Matlab的输出相匹配):

  

谱密度是周期图的平均值,按比例缩放   频谱下的面积与数据的均方值相同。

换句话说,
enter image description here
而上面提供的缩放因子适用于定义,其中缩放使得离散频谱值的总和与数据的均方值相同 (始终符合Half-complex packing的期望):
enter image description here

因此,定义的差异引入了额外的WINDOW_SIZE*sampling_rate因子(请注意,如果没有指定pwelch的第四个参数,则使用默认的sampling_rate(1Hz)。

因此,要使C版本的半频谱输出与pwelch匹配,您需要:

norm = count*Wss/(2*WINDOW_SIZE*sampling_rate);
powVal = outputData[0]/(2*norm);
fprintf(outputFile,"%lf ",powVal);
for (index1 =1; index1<windowSize/2;index1++){
  powVal = outputData[index1]/norm;
  fprintf(outputFile,"%lf ",powVal);
}
powVal = outputData[windowSize/2]/(2*norm);
fprintf(outputFile,"%lf ",powVal);

或者,要缩放pwelch输出以匹配C程序中使用的定义:

% For arbitrary sampling_rate:
%[output,f] = pwelch(input,hann(8192),[],[],sampling_rate)/(8192*sampling_rate);
% which simplifies to the following by setting sampling_rate = 1
[output,f] = pwelch(input,hann(8192))/8192;
plot(output);

答案 1 :(得分:1)

outputData[]的元素未初始化。

outputData = (double*) fftw_malloc(sizeof(double)*windowSize);
...
  outputData[index1] += ...

推荐:

outputData = fftw_malloc(sizeof(double)*windowSize);
for (index1 =0; index1 < windowSize; index1++) {
  outputData[index1] = 0.0;
}
...
  outputData[index1] += ...
相关问题