用C语言编写一个简单的实数输入离散傅里叶变换
所以我试图用C语言编写离散傅里叶变换来处理真正的32位浮点wav文件。它一次读取2帧(每个通道一帧,但出于我的目的,我假设它们都是相同的,所以我使用帧[0])。该代码应该通过探测频率20,40,60,…,10000来写出输入文件的振幅谱。我在输入帧上使用汉宁窗口。如果可以的话,我想避免使用复数。当我运行这个程序时,它给了我一些非常奇怪的振幅(大多数振幅非常小,与正确的频率无关),这让我相信我在计算中犯了一个根本性的错误。有人能提供一些关于这里发生的事情的见解吗?这是我的密码:用C语言编写一个简单的实数输入离散傅里叶变换,c,dft,windowing,C,Dft,Windowing,所以我试图用C语言编写离散傅里叶变换来处理真正的32位浮点wav文件。它一次读取2帧(每个通道一帧,但出于我的目的,我假设它们都是相同的,所以我使用帧[0])。该代码应该通过探测频率20,40,60,…,10000来写出输入文件的振幅谱。我在输入帧上使用汉宁窗口。如果可以的话,我想避免使用复数。当我运行这个程序时,它给了我一些非常奇怪的振幅(大多数振幅非常小,与正确的频率无关),这让我相信我在计算中犯了一个根本性的错误。有人能提供一些关于这里发生的事情的见解吗?这是我的密码: int windo
int windowSize = 2205;
int probe[500];
float hann[2205];
int j, n;
// initialize probes to 20,40,60,...,10000
for (j=0; j< len(probe); j++) {
probe[j] = j*20 + 20;
fprintf(f, "%d\n", probe[j]);
}
fprintf(f, "-1\n");
// setup the Hann window
for (n=0; n< len(hann); n++) {
hann[n] = 0.5*(cos((2*M_PI*n/(float)windowSize) + M_PI))+0.5;
}
float angle = 0.0;
float w = 0.0; // windowed sample
float realSum[len(probe)]; // stores the real part of the probe[j] within a window
float imagSum[len(probe)]; // stores the imaginary part of probe[j] within window
float mag[len(probe)]; // stores the calculated amplitude of probe[j] within a window
for (j=0; j<len(probe);j++) {
realSum[j] = 0.0;
imagSum[j] = 0.0;
mag[j] = 0.0;
}
n=0; //count number of samples within current window
framesread = psf_sndReadFloatFrames(ifd,frame,1);
totalread = 0;
while (framesread == 1){
totalread++;
// window the frame with hann value at current sample
w = frame[0]*hann[n];
// determine both real and imag product values at sample n for all probe freqs times the windowed signal
for (j=0; j<len(probe);j++) {
angle = (2.0 * M_PI * probe[j] * n) / windowSize;
realSum[j] = realSum[j] + (w * cos(angle));
imagSum[j] = imagSum[j] + (w * sin(angle));
}
n++;
// checks to see if current window has ended
if (totalread % windowSize == 0) {
fprintf(f, "B(%f)\n", totalread/44100.0);
printf("%f breakpoint written\n", totalread/44100.0);
for (j=0; j < len(mag); j++) { // print out the amplitudes
realSum[j] = realSum[j]/windowSize;
imagSum[j] = imagSum[j]/windowSize;
mag[j] = sqrt(pow((double)realSum[j],2)+pow((double)imagSum[j],2))/windowSize;
fprintf(f, "%d\t%f\n", probe[j], mag[j]);
realSum[j] = 0.0;
imagSum[j] = 0.0;
}
n=0;
}
framesread = psf_sndReadFloatFrames(ifd,frame,1);
}
int windowSize=2205;
int探针[500];
浮动汉恩[2205];
int j,n;
//将探测初始化为20,40,60,…,10000
对于(j=0;j 对于(j=0;j和下面的代码-只是稍微重新组织以编译和创建假样本,我没有得到全部零。我已将输出调用更改为结尾处的,从:
fprintf(f, "%d\t%f\n", probe[j], mag[j] );
到
这只会使查看非零数据变得更容易。也许唯一的问题是理解比例因子?请注意,我是如何伪造输入以生成纯音作为测试用例的
#include <math.h>
#include <stdio.h>
#define M_PI 3.1415926535
#define SAMPLE_RATE 44100.0f
#define len(array) (sizeof array/sizeof *array)
unsigned psf_sndReadFloatFrames(FILE* inFile,float* frame,int framesToRead)
{
static float counter = 0;
float frequency = 1000;
float time = counter++;
float phase = time/SAMPLE_RATE*frequency;
*frame = (float)sin(phase);
return counter < SAMPLE_RATE;
}
void discreteFourier(FILE* f)
{
FILE* ifd = 0;
float frame[1];
int windowSize = 2205;
int probe[500];
float hann[2205];
float angle = 0.0;
float w = 0.0; // windowed sample
float realSum[len(probe)]; // stores the real part of the probe[j] within a window
float imagSum[len(probe)]; // stores the imaginary part of probe[j] within window
float mag[len(probe)]; // stores the calculated amplitude of probe[j] within a window
int j, n;
unsigned framesread = 0;
unsigned totalread = 0;
for (j=0; j<len(probe);j++) {
realSum[j] = 0.0;
imagSum[j] = 0.0;
mag[j] = 0.0;
}
// initialize probes to 20,40,60,...,10000
for (j=0; j< len(probe); j++) {
probe[j] = j*20 + 20;
fprintf(f, "%d\n", probe[j]);
}
fprintf(f, "-1\n");
// setup the Hann window
for (n=0; n< len(hann); n++)
{
hann[n] = 0.5*(cos((2*M_PI*n/(float)windowSize) + M_PI))+0.5;
}
n=0; //count number of samples within current window
framesread = psf_sndReadFloatFrames(ifd,frame,1);
totalread = 0;
while (framesread == 1){
totalread++;
// window the frame with hann value at current sample
w = frame[0]*hann[n];
// determine both real and imag product values at sample n for all probe freqs times the windowed signal
for (j=0; j<len(probe);j++) {
angle = (2.0 * M_PI * probe[j] * n) / windowSize;
realSum[j] = realSum[j] + (w * cos(angle));
imagSum[j] = imagSum[j] + (w * sin(angle));
}
n++;
// checks to see if current window has ended
if (totalread % windowSize == 0) {
fprintf(f, "B(%f)\n", totalread/SAMPLE_RATE);
printf("%f breakpoint written\n", totalread/SAMPLE_RATE);
for (j=0; j < len(mag); j++) { // print out the amplitudes
realSum[j] = realSum[j]/windowSize;
imagSum[j] = imagSum[j]/windowSize;
mag[j] = sqrt(pow((double)realSum[j],2)+pow((double)imagSum[j],2))/windowSize;
if (mag[j] > 1e-7)
fprintf(f, "%d\t%f\n", probe[j], mag[j] * 10000);
realSum[j] = 0.0;
imagSum[j] = 0.0;
}
n=0;
}
framesread = psf_sndReadFloatFrames(ifd,frame,1);
}
}
#包括
#包括
#定义M_PI 3.1415926535
#定义采样率44100.0f
#定义len(数组)(sizeof数组/sizeof*数组)
未签名的psf_浮动帧(文件*内嵌、浮动*帧、整型framesToRead)
{
静态浮点计数器=0;
浮动频率=1000;
浮动时间=计数器++;
浮动相位=时间/采样率*频率;
*帧=(浮动)sin(相位);
返回计数器<采样率;
}
void discreteFourier(文件*f)
{
文件*ifd=0;
浮动帧[1];
int windowSize=2205;
int探针[500];
浮动汉恩[2205];
浮动角度=0.0;
float w=0.0;//带窗口的示例
float realSum[len(probe)];//在窗口中存储probe[j]的实部
float imagSum[len(probe)];//在窗口中存储probe[j]的虚部
float mag[len(probe)];//将探针[j]的计算振幅存储在窗口中
int j,n;
无符号帧read=0;
无符号totalread=0;
对于(j=0;j我认为误差在于角度的计算。每个样本的角度增量取决于采样频率。
类似这样的情况(您似乎有44100Hz):
您的示例窗口将包含最低探测频率20Hz的一个完整周期。如果将n循环到2205,则该角度将为2*M_PI。
您看到的可能是混叠,因为您的参考频率为2205Hz,1102Hz以上的所有频率都混叠为较低的频率。没有发现明显的错误,但我建议生成测试用例并检查系数的数学属性是否正确-例如,实值输入表示对称系数@基思,对不起,我不确定这到底是什么意思。在这种情况下,系数是什么?它是变量w吗?我试着在440赫兹的A4上运行它,DFT在整个持续时间内每一个频率返回几乎0.00000。如果一切都为零,你有一个更大的问题。请参阅答案。如果目标是进行转换形式,而不是学习写一个,考虑使用OpenCV。是的,它是一个战舰交换一个苍蝇,但会做你需要的。还有FFTW库做傅立叶变换。
#include <math.h>
#include <stdio.h>
#define M_PI 3.1415926535
#define SAMPLE_RATE 44100.0f
#define len(array) (sizeof array/sizeof *array)
unsigned psf_sndReadFloatFrames(FILE* inFile,float* frame,int framesToRead)
{
static float counter = 0;
float frequency = 1000;
float time = counter++;
float phase = time/SAMPLE_RATE*frequency;
*frame = (float)sin(phase);
return counter < SAMPLE_RATE;
}
void discreteFourier(FILE* f)
{
FILE* ifd = 0;
float frame[1];
int windowSize = 2205;
int probe[500];
float hann[2205];
float angle = 0.0;
float w = 0.0; // windowed sample
float realSum[len(probe)]; // stores the real part of the probe[j] within a window
float imagSum[len(probe)]; // stores the imaginary part of probe[j] within window
float mag[len(probe)]; // stores the calculated amplitude of probe[j] within a window
int j, n;
unsigned framesread = 0;
unsigned totalread = 0;
for (j=0; j<len(probe);j++) {
realSum[j] = 0.0;
imagSum[j] = 0.0;
mag[j] = 0.0;
}
// initialize probes to 20,40,60,...,10000
for (j=0; j< len(probe); j++) {
probe[j] = j*20 + 20;
fprintf(f, "%d\n", probe[j]);
}
fprintf(f, "-1\n");
// setup the Hann window
for (n=0; n< len(hann); n++)
{
hann[n] = 0.5*(cos((2*M_PI*n/(float)windowSize) + M_PI))+0.5;
}
n=0; //count number of samples within current window
framesread = psf_sndReadFloatFrames(ifd,frame,1);
totalread = 0;
while (framesread == 1){
totalread++;
// window the frame with hann value at current sample
w = frame[0]*hann[n];
// determine both real and imag product values at sample n for all probe freqs times the windowed signal
for (j=0; j<len(probe);j++) {
angle = (2.0 * M_PI * probe[j] * n) / windowSize;
realSum[j] = realSum[j] + (w * cos(angle));
imagSum[j] = imagSum[j] + (w * sin(angle));
}
n++;
// checks to see if current window has ended
if (totalread % windowSize == 0) {
fprintf(f, "B(%f)\n", totalread/SAMPLE_RATE);
printf("%f breakpoint written\n", totalread/SAMPLE_RATE);
for (j=0; j < len(mag); j++) { // print out the amplitudes
realSum[j] = realSum[j]/windowSize;
imagSum[j] = imagSum[j]/windowSize;
mag[j] = sqrt(pow((double)realSum[j],2)+pow((double)imagSum[j],2))/windowSize;
if (mag[j] > 1e-7)
fprintf(f, "%d\t%f\n", probe[j], mag[j] * 10000);
realSum[j] = 0.0;
imagSum[j] = 0.0;
}
n=0;
}
framesread = psf_sndReadFloatFrames(ifd,frame,1);
}
}
angle = (2.0 * M_PI * probe[j] * n) / 44100;