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;
}