我正在尝试制作一个计算时间系列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);
导入c
程序的结果后,PSD是相同的,但规模不同:
正如您所看到的那样,规模并不相同。
答案 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的输出相匹配):
谱密度是周期图的平均值,按比例缩放 频谱下的面积与数据的均方值相同。
换句话说,
而上面提供的缩放因子适用于定义,其中缩放使得离散频谱值的总和与数据的均方值相同
(始终符合Half-complex packing的期望):
因此,定义的差异引入了额外的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] += ...