C 功率谱密度的计算

C 功率谱密度的计算,c,signal-processing,fftw,C,Signal Processing,Fftw,我试图通过使用fftw3库获得真实数据集的PSD 为了进行测试,我编写了一个如下所示的小程序,它生成一个遵循正弦函数的信号 #include <stdio.h> #include <math.h> #define PI 3.14 int main (){ double value= 0.0; float frequency = 5; int i = 0 ; double time = 0.0; FILE* outputFile

我试图通过使用
fftw3
库获得真实数据集的PSD 为了进行测试,我编写了一个如下所示的小程序,它生成一个遵循正弦函数的信号

#include <stdio.h>
#include <math.h>
#define PI 3.14

int main (){
    double  value= 0.0;
    float frequency = 5;
    int i = 0 ; 
    double time = 0.0;
    FILE* outputFile = NULL;
    outputFile = fopen("sinvalues","wb+");
    if(outputFile==NULL){
        printf(" couldn't open the file \n");
        return -1;
    }

    for (i = 0; i<=5000;i++){

        value =  sin(2*PI*frequency*zeit);
        fwrite(&value,sizeof(double),1,outputFile);
        zeit += (1.0/frequency);
    }
    fclose(outputFile);
    return 0;

}
#包括
#包括
#定义PI 3.14
int main(){
双值=0.0;
浮动频率=5;
int i=0;
双倍时间=0.0;
FILE*outputFile=NULL;
outputFile=fopen(“sinvalues”、“wb+”);
if(outputFile==NULL){
printf(“无法打开文件\n”);
返回-1;
}

对于(i=0;i我不确定你的问题是什么。根据提供的信息,你的结果似乎是合理的

正如你必须知道的,PSD是自相关函数的傅里叶变换。对于正弦波输入,你的AC函数是周期性的,因此PSD会有音调,就像你画的那样

我的“答案”实际上是一些关于调试的思想发起者。如果我们可以发布公式,对所有相关人员来说都会更容易。你可能知道,现在SE上有一个信号处理部分

首先,你应该给我们一个交流函数的曲线图。你所显示的PSD的逆FT是周期音的线性组合

第二,试着移除窗口,只要把它做成一个盒子,或者如果可以的话跳过这一步

第三,尝试用FFT替换DFT(我只浏览了fftw3库文档,也许这是一个选项)

最后,尝试输入白噪声。您可以使用伯努利距离,或仅使用高斯距离。AC将是一个增量函数,尽管样本AC不会。这将为您提供(样本)白色PSD分布


我希望这些建议能有所帮助。

您将错误的输出值组合到功率谱线。在
result
的开头有
windowsSize/2+1
实值,在结尾有
windowsSize/2-1
虚值,顺序相反。这是因为第一个(0Hz)和最后一个(0Hz)的虚值(奈奎斯特频率)谱线为0

int spectrum_lines = windowsSize / 2 + 1;
power_spectrum = (double *)malloc( sizeof(double) * spectrum_lines );

power_spectrum[0] = result[0] * result[0];
for ( i = 1 ; i < windowsSize / 2 ; i++ )
    power_spectrum[i] = result[i]*result[i] + result[windowsSize-i]*result[windowsSize-i];
power_spectrum[i] = result[i] * result[i];

对预期输出函数的一些注释

  • 您的输入是一个具有纯实数值的函数。 DFT的结果具有复数值。 因此,您必须声明变量out不是double,而是fftw_complex*out

  • 通常,dft输入值的数量与输出值的数量相同。 然而,dft的输出谱包含正的复振幅 频率以及负频率

  • 在纯实输入的特殊情况下,正频率的振幅为 负频率振幅的共轭复值。 因此,仅计算正频谱的频率, 这意味着复杂输出值的数量是 实际输入值的数目

  • 如果您的输入是简单的正弦波,则频谱仅包含一个频率分量。 对于10个、100个、1000个甚至更多的输入样本,这是正确的。 所有其他值都是零。因此,处理大量输入值没有任何意义

  • 如果输入数据集包含单个周期,则复杂的输出值为 包含在out[1]中

  • 如果输入数据集包含M个完整周期,在您的案例5中, 因此,结果存储在out[5]中

  • 我对你的代码做了一些修改。为了让一些事实更清楚


#包括
#包括
#包括
#包括
#包括“fftw3.h”
int performDFT(int nbrof输入样本,字符*文件名)
{
输出样本数量;
双*英寸;
fftw_复合体*out;
fftw_计划p;
//对于纯实数输入数据,
//正频率和负频率的输出值
//是共轭复值。
//这意味着,不需要计算两者。
//如果有正频率的复值,
//你可以通过以下方法计算负频率的值
//更改值的虚部的符号
//因此,复数输出值的数量(频率分量的振幅)
//是实际输入值数量的一半(时域中的振幅):
NBROFIUTSAMPLES=ceil(NBROFIUTSAMPLES/2.0);
//创建具有实际输入和复杂输出的1D DFT计划
in=(双*)fftw_malloc(双*)输入样本的大小);
out=(fftw_复合物*)fftw_malloc(尺寸(fftw_复合物)*NBROF输出样品);
p=fftw\U平面图\U dft\U r2c\U 1d(输入样本数量、输入、输出、fftw\U估算);
//将数据从输入文件读取到输入数组
FILE*inputFile=NULL;
inputFile=fopen(文件名,“r”);
if(inputFile==NULL){
fprintf(标准输出,“无法打开文件%s\n”,文件名);
返回-1;
}
双重价值;
int-idx=0;
而(!feof(inputFile)){
fscanf(输入文件、%lf、&value);
在[idx++]=值中;
}
fclose(输入文件);
//执行dft
fftw_执行(p);
//打印输出结果
char outputFileName[]=“dftvalues.txt”;
FILE*outputFile=NULL;
outputFile=fopen(outputFileName,“w+”);
if(outputFile==NULL){
fprintf(标准输出,“无法打开文件%s\n”,输出文件名);
返回-1;
}
双重真实;
双imagVal;
双倍功率;
双空位;
fprintf(标准值,“频率实图像Abs电源”);

对于(idx=0;idxIn)您似乎要声明
time
并使用
zeit
的第一个程序。这不应该编译,除非您的编译器懂德语。不,我只是更改SO@Engine您正在以读取模式(rb)打开“sinvalues”并在其上进行写入。您不应该使用“wb”吗在做fopen?时,我重写了程序,但我忘了纠正这个错误。我的SIN值是正确的。你“重写”了多少?正如帖子所说,它正在生成一个
int spectrum_lines = windowsSize / 2 + 1;
power_spectrum = (double *)malloc( sizeof(double) * spectrum_lines );

power_spectrum[0] = result[0] * result[0];
for ( i = 1 ; i < windowsSize / 2 ; i++ )
    power_spectrum[i] = result[i]*result[i] + result[windowsSize-i]*result[windowsSize-i];
power_spectrum[i] = result[i] * result[i];
#define PI 3.141592653589793 // This has to be absolutely exact!

int windowSize = 512;        // Total number of created samples in the test signal
int numberOfPeriods = 64;    // Total number of sinoid periods in the test signal
for ( n = 0 ; n < windowSize ; ++n ) {
    value = sin( (2 * PI * numberOfPeriods * n) / windowSize );
    fwrite( &value, sizeof(double), 1, outputFile );
}
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "fftw3.h"

int performDFT(int nbrOfInputSamples, char *fileName)
{
    int nbrOfOutputSamples;
    double *in;
    fftw_complex *out;
    fftw_plan p;

    // In the case of pure real input data,
    // the output values of the positive frequencies and the negative frequencies
    // are conjugated complex values.
    // This means, that there no need for calculating both.
    // If you have the complex values for the positive frequencies,
    // you can calculate the values of the negative frequencies just by
    // changing the sign of the value's imaginary part
    // So the number of complex output values ( amplitudes of frequency components)
    // are the half of the number of the real input values ( amplitutes in time domain):
    nbrOfOutputSamples = ceil(nbrOfInputSamples/2.0);

    // Create a plan for a 1D DFT with real input and complex output
    in = (double*) fftw_malloc(sizeof(double) * nbrOfInputSamples);
    out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * nbrOfOutputSamples);
    p = fftw_plan_dft_r2c_1d(nbrOfInputSamples, in, out, FFTW_ESTIMATE);

    // Read data from input file to input array
    FILE* inputFile = NULL;
    inputFile = fopen(fileName,"r");
    if(inputFile==NULL){
        fprintf(stdout,"couldn't open the file %s\n", fileName);
        return -1;
    }
    double value;
    int     idx = 0;
    while(!feof(inputFile)){
        fscanf(inputFile, "%lf", &value);
        in[idx++] = value;       
    }
    fclose(inputFile);

    // Perform the dft
    fftw_execute(p);

    // Print output results
    char outputFileName[] = "dftvalues.txt";
    FILE* outputFile = NULL;
   outputFile = fopen(outputFileName,"w+");
    if(outputFile==NULL){
        fprintf(stdout,"couldn't open the file %s\n", outputFileName);
        return -1;
    }
    double  realVal;
    double  imagVal;
    double  powVal;
    double  absVal;

    fprintf(stdout, "     Frequency  Real       Imag        Abs       Power\n");
    for (idx=0; idx<nbrOfOutputSamples; idx++) {
        realVal = out[idx][0]/nbrOfInputSamples; // Ideed nbrOfInputSamples is correct!
        imagVal = out[idx][1]/nbrOfInputSamples; // Ideed nbrOfInputSamples is correct!
        powVal  = 2*(realVal*realVal + imagVal*imagVal);
        absVal  = sqrt(powVal/2);
        if (idx == 0) {
            powVal /=2;
        }
        fprintf(outputFile, "%10i %10.4lf %10.4lf %10.4lf %10.4lf\n", idx, realVal, imagVal, absVal, powVal);
        fprintf(stdout,     "%10i %10.4lf %10.4lf %10.4lf %10.4lf\n", idx, realVal, imagVal, absVal, powVal);
        // The total signal power of a frequency is the sum of the power of the posive and the negative frequency line.
        // Because only the positive spectrum is calculated, the power is multiplied by two.
        // However, there is only one single line in the prectrum for DC.
        // This means, the DC value must not be doubled.

    }
    fclose(outputFile);


    // Clean up
    fftw_destroy_plan(p);
    fftw_free(in); fftw_free(out);

    return 0;

}

int main(int argc, const char * argv[]) {
    // Set basic parameters
    float   timeIntervall = 1.0;     // in seconds
    int     nbrOfSamples = 50;      //  number of Samples per time intervall, so the unit is S/s
    double  timeStep = timeIntervall/nbrOfSamples; // in seconds
    float   frequency = 5;          // frequency in Hz

    // The period time of the signal is 1/5Hz = 0.2s
    // The number of samples per period is: nbrOfSamples/frequency = (50S/s)/5Hz = 10S
    // The number of periods per time intervall is: frequency*timeIntervall = 5Hz*1.0s = (5/s)*1.0s = 5



    // Open file for writing signal values
    char fileName[] = "sinvalues.txt";
    FILE* outputFile = NULL;
    outputFile = fopen(fileName,"w+");
    if(outputFile==NULL){
        fprintf(stdout,"couldn't open the file %s\n", fileName);
        return -1;
    }

    // Calculate signal values and write them to file
    double  time;
    double  value;
    double  dcValue = 0.2;
    int idx = 0;
    fprintf(stdout, "     SampleNbr   Signal value\n");
    for (time = 0; time<=timeIntervall; time += timeStep){
        value =  sin(2*M_PI*frequency*time) + dcValue;
        fprintf(outputFile, "%lf\n",value);
        fprintf(stdout, "%10i %15.5f\n",idx++, value);
    }
    fclose(outputFile);

    performDFT(nbrOfSamples, fileName);
    return 0;

}