- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试开发一个简单的c应用程序,它可以在wav文件中给定时间戳的特定频率范围内给出0-100之间的值。
示例:我的频率范围为44.1kHz(典型的MP3文件),我想将该范围拆分为n个范围(从0开始)。然后我需要得到每个范围的振幅,从0到100。
我目前所做的:
使用libsndfile,我现在可以读取wav文件的数据。
infile = sf_open(argv [1], SFM_READ, &sfinfo);
float samples[sfinfo.frames];
sf_read_float(infile, samples, 1);
double blackman_harris(int n, int N){
double a0, a1, a2, a3, seg1, seg2, seg3, w_n;
a0 = 0.35875;
a1 = 0.48829;
a2 = 0.14128;
a3 = 0.01168;
seg1 = a1 * (double) cos( ((double) 2 * (double) M_PI * (double) n) / ((double) N - (double) 1) );
seg2 = a2 * (double) cos( ((double) 4 * (double) M_PI * (double) n) / ((double) N - (double) 1) );
seg3 = a3 * (double) cos( ((double) 6 * (double) M_PI * (double) n) / ((double) N - (double) 1) );
w_n = a0 - seg1 + seg2 - seg3;
return w_n;
}
int main (int argc, char * argv [])
{ char *infilename ;
SNDFILE *infile = NULL ;
FILE *outfile = NULL ;
SF_INFO sfinfo ;
infile = sf_open(argv [1], SFM_READ, &sfinfo);
int N = pow(2, 10);
fftw_complex results[N/2 +1];
double samples[N];
sf_read_double(infile, samples, 1);
double normalizer;
int k;
for(k = 0; k < N;k++){
if(k == 0){
normalizer = blackman_harris(k, N);
} else {
normalizer = blackman_harris(k, N);
}
}
normalizer = normalizer * (double) N/2;
fftw_plan p = fftw_plan_dft_r2c_1d(N, samples, results, FFTW_ESTIMATE);
fftw_execute(p);
int i;
for(i = 0; i < N/2 +1; i++){
double value = ((double) sqrtf(creal(results[i])*creal(results[i])+cimag(results[i])*cimag(results[i]))/normalizer);
printf("%f\n", value);
}
sf_close (infile) ;
return 0 ;
} /* main */
最佳答案
这一切都取决于你所追求的频率范围。fft的工作原理是抽取2^n个样本,并为您提供2^(n-1)个实数和虚数。我不得不承认,我对这些价值观到底代表着什么感到很模糊(我有一个朋友答应和我一起经历这一切,而不是我在他有经济问题时借给他的贷款);而不是一个圈子里的角度。有效地,它们为每个频率仓的正弦和余弦提供了角度参数的arccos,从中可以完美地重建原始2^n样本。
无论如何,这有一个巨大的优势,你可以通过计算实部和虚部的欧几里德距离(sqrtf((实部*实部)+(imag*imag)))来计算震级。这将为您提供一个不规范的距离值。然后,可以使用该值为每个频带建立一个幅值。
所以我们取10阶fft(2^10)。输入1024个样本。对这些样本进行fft运算,得到512个虚值和实值(这些值的特定顺序取决于使用的fft算法)。因此,这意味着对于44.1kHz音频文件,每个bin代表44100/512Hz或~86Hz/bin。
其中一个突出的特点是,如果你使用更多的样本(在处理图像等多维信号时来自所谓的时间或空间域),你会得到更好的频率表示(在所谓的频率域)。不管你如何牺牲一个来换取另一个。这就是事情的发展方向,你必须接受它。
基本上,您需要调整频率箱和时间/空间分辨率,以获得所需的数据。
首先是一些术语。我前面提到的1024个时域示例称为您的窗口。通常,在执行这种类型的处理时,您需要将窗口滑动一定量,以获取下一个1024个fft采样。很明显,要做的事情是采集样本0->1023,然后1024->2047,以此类推。不幸的是,这并不能带来最好的结果。理想情况下,您希望在一定程度上重叠窗口,以便随着时间的推移获得更平滑的频率变化。最常见的是人们把窗户滑动一半。你的第一个窗口是0->1023,第二个是512->1535,以此类推。
现在这又引出了一个问题。虽然这些信息提供了完美的反fft信号重建,但它在一定程度上给您留下了一个问题,即频率会泄漏到包围盒中。为了解决这个问题,一些数学家(比我聪明得多)提出了awindow function的概念。窗口函数在频域提供了更好的频率隔离,但会导致时域信息的丢失(即在使用窗口函数afaik后无法完全重新构造信号)。
现在有各种类型的窗口函数,从矩形窗口(实际上对信号没有任何作用)到提供更好的频率隔离的各种函数(尽管有些函数可能会杀死您可能感兴趣的周围频率!)!)。唉,没有一种尺寸适合所有人,但我是Blackmann-Harris窗口函数的忠实粉丝。我认为它给了最好的结果!
不过,正如我前面提到的,fft为您提供了一个非标准化的频谱。要使光谱正常化(在欧几里德距离计算之后),需要用一个标准化因子来划分所有值(我将更详细地介绍here)。
这种正常化将为您提供一个介于0和1之间的值。所以你可以很容易地将这个值乘以100,得到你的0到100的比例。
然而,这并不是它的终点。你从中得到的光谱相当不令人满意。这是因为你是在用线性比例来观察震级。不幸的是,人类的耳朵使用对数音阶。这会引起光谱图/光谱的外观问题。
要解决这个问题,您需要将这些0到1的值(我称之为“x”)转换为分贝刻度。标准转换是20.0f * log10f( x )。这将为您提供一个值,其中1已转换为0,0已转换为-无穷大。你的震级现在在适当的对数范围内。然而,这并不总是那么有帮助。
此时,您需要查看原始采样位深度。在16位采样时,会得到一个介于32767和-32768之间的值。这意味着您的dynamic range是fabsf(20.0f*log10f(1.0f/65536.0f))或~96.33db。所以现在我们有了这个价值。
取上面db计算得到的值。加上-96.33这个值。显然,最大振幅(0)现在是96.33。现在didivde得到了相同的值,你现在得到了一个从-infinity到1.0f的值,把下端夹紧到0,你现在得到了一个从0到1的范围,然后乘以100,最后得到了0到100的范围。
这是一个比我最初想要的更大的帖子,但是应该给你一个很好的基础,如何为一个输入信号产生一个好的光谱/谱图。
呼吸
进一步阅读(对于已经找到的原海报以外的人):
Converting an FFT to a spectogram
编辑:顺便说一句,我发现kiss-fft更容易使用,我执行前向fft的代码如下:
CFFT::CFFT( unsigned int fftOrder ) :
BaseFFT( fftOrder )
{
mFFTSetupFwd = kiss_fftr_alloc( 1 << fftOrder, 0, NULL, NULL );
}
bool CFFT::ForwardFFT( std::complex< float >* pOut, const float* pIn, unsigned int num )
{
kiss_fftr( mFFTSetupFwd, pIn, (kiss_fft_cpx*)pOut );
return true;
}
关于c - WAV文件分析C(libsndfile,fftw3),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10627517/
我刚刚继承了一个旧的 PostgreSQL 安装,需要进行一些诊断以找出该数据库运行缓慢的原因。在 MS SQL 上,您可以使用 Profiler 等工具来查看正在运行的查询,然后查看它们的执行计划。
将目标从Analytics(分析)导入到AdWords中,然后在Analytics(分析)中更改目标条件时,是否可以通过更改将目标“重新导入”到AdWords,还是可以自动选择? 最佳答案 更改目标值
我正在使用google analytics api来获取数据。我正在获取数据,但我想验证两个参数,它们在特定日期范围内始终为0。我正在获取['ga:transactions']和['ga:goalCo
我使用Google API从Google Analytics(分析)获取数据,但指标与Google Analytics(分析)的网络界面不同。 即:我在2015年3月1日获得数据-它返回综合浏览量79
我在我的Web应用程序中使用sammy.js进行剔除。我正在尝试向其中添加Google Analytics(分析)。我很快找到了following plugin来实现页面跟踪。 我按照步骤操作,页面如
当使用 Xcode 分析 (product>analyze) 时,有没有办法忽略给定文件中的任何错误? 例如编译指示之类的? 我们只想忽略第三方代码的任何警告,这样当我们的代码出现问题时,它对我们
目录 EFK 1. 日志系统 2. 部署ElasticSearch 2.1 创建handless服务 2.2 创建s
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
GCC/G++ 是否有可用于输出分析的选项? 能够比较以前的代码与新代码之间的差异(大小、类/结构的大小)将很有用。然后可以将它们与之前的输出进行比较以进行比较,这对于许多目的都是有用的。 如果没有此
我正在浏览 LYAH,并一直在研究处理列表时列表理解与映射/过滤器的使用。我已经分析了以下两个函数,并包含了教授的输出。如果我正确地阅读了教授的内容,我会说 FiltB 的运行速度比 FiltA 慢很
在 MySQL 中可以使用 SET profiling = 1; 设置分析 查询 SHOW PROFILES; 显示每个查询所用的时间。我想知道这个时间是只包括服务器的执行时间还是还包括将结果发送到前
我用 Python 编写了几个用于生成阶乘的模块,我想测试运行时间。我找到了一个分析示例 here我使用该模板来分析我的模块: import profile #fact def main():
前几天读了下mysqld_safe脚本,个人感觉还是收获蛮大的,其中细致的交代了MySQL数据库的启动流程,包括查找MySQL相关目录,解析配置文件以及最后如何调用mysqld程序来启动实例等,有着
上一篇:《人工智能大语言模型起源篇,低秩微调(LoRA)》 (14)Rae 和同事(包括78位合著者!)于2022年发表的《Scaling Language Models: Methods, A
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
我有四列形式的数据。前三列代表时间,value1,value 2。第四列是二进制,全为 0 或 1。当第四列中对应的二进制值为0时,有没有办法告诉excel删除时间、值1和值2?我知道这在 C++ 或
我正在运行一个进行长时间计算的 Haskell 程序。经过一些分析和跟踪后,我注意到以下内容: $ /usr/bin/time -v ./hl test.hl 9000045000050000 Com
我有一个缓慢的 asp.net 程序正在运行。我想分析生产服务器以查看发生了什么,但我不想显着降低生产服务器的速度。 一般而言,配置生产盒或仅本地开发盒是标准做法吗?另外,您建议使用哪些程序来实现这一
我目前正在尝试分析 Haskell 服务器。服务器永远运行,所以我只想要一个固定时间的分析报告。我尝试只运行该程序 3 分钟,然后礼貌地要求它终止,但不知何故,haskell 分析器不遵守术语信号,并
我是一名优秀的程序员,十分优秀!