声音样本的数学分析(作为数字数组)

时间:2021-02-11 20:16:08

I need to find the frequency of a sample, stored (in vb) as an array of byte. Sample is a sine wave, known frequency, so I can check), but the numbers are a bit odd, and my maths-foo is weak. Full range of values 0-255. 99% of numbers are in range 235 to 245, but there are some outliers down to 0 and 1, and up to 255 in the remaining 1%. How do I normalise this to remove outliers, (calculating the 235-245 interval as it may change with different samples), and how do I then calculate zero-crossings to get the frequency? Apologies if this description is rubbish!

我需要找到一个样本的频率,存储(在vb中)作为一个字节数组。样本是一个正弦波,已知频率,所以我可以检查),但数字有点奇怪,我的数学foo很弱。全系列值0-255。 99%的数字在235到245的范围内,但有一些异常值降至0和1,其余1%则高达255。如何对此进行归一化以去除异常值(计算235-245间隔,因为它可能随着不同的样本而变化),以及如何计算过零以获得频率?如果这个描述是垃圾,请道歉!

7 个解决方案

#1


6  

The FFT is probably the best answer, but if you really want to do it by your method, try this:

FFT可能是最好的答案,但如果您真的想通过您的方法来做,请尝试以下方法:

To normalize, first make a histogram to count how many occurrances of each value from 0 to 255. Then throw out X percent of the values from each end with something like:

要进行标准化,首先要制作一个直方图,以计算从0到255的每个值的出现次数。然后从每个端点丢弃X%的值,例如:

for (i=lower=0;i< N*(X/100); lower++)
  i+=count[lower];
//repeat in other direction for upper

Now normalize with

现在正常化

A[i] = 255*(A[i]-lower)/(upper-lower)-128

Throw away results outside the -128..127 range.

抛弃-128..127范围之外的结果。

Now you can count zero crossings. To make sure you are not fooled by noise, you might want to keep track of the slope over the last several points, and only count crossings when the average slope is going the right way.

现在你可以计算过零点。为了确保您不会受到噪音的愚弄,您可能希望跟踪最后几个点的斜率,并且仅在平均斜率正确的情况下计算交叉点。

#2


5  

The standard method to attack this problem is to consider one block of data, hopefully at least twice the actual frequency (taking more data isn't bad, so it's good to overestimate a bit), then take the FFT and guess that the frequency corresponds to the largest number in the resulting FFT spectrum.

解决这个问题的标准方法是考虑一个数据块,希望至少是实际频率的两倍(获取更多数据也不错,所以高估一点是好的),然后采用FFT并猜测频率对应得到的FFT频谱中的最大数字。

By the way, very similar problems have been asked here before - you could search for those answers as well.

顺便说一下,之前已经提出过非常类似的问题 - 您也可以搜索这些答案。

#3


3  

Use the Fourier transform, it's much more noise insensitive than counting zero crossings

使用傅立叶变换,它比计算零交叉更加噪声不敏感

Edit: @WaveyDavey

I found an F# library to do an FFT: From here

我找到了一个F#库来做FFT:从这里开始

As it turns out, the best free implementation that I've found for F# users so far is still the fantastic FFTW library. Their site has a precompiled Windows DLL. I've written minimal bindings that allow thread-safe access to FFTW from F#, with both guru and simple interfaces. Performance is excellent, 32-bit Windows XP Pro is only up to 35% slower than 64-bit Linux.

事实证明,到目前为止,我为F#用户找到的最佳免费实现仍然是非常棒的FFTW库。他们的网站有一个预编译的Windows DLL。我编写了最小的绑定,允许从F#线程安全地访问FFTW,同时使用guru和简单的接口。性能非常出色,32位Windows XP Pro比64位Linux慢了35%。

Now I'm sure you can call F# lib from VB.net, C# etc, that should be in their docs

现在我确定你可以从VB.net,C#等调用F#lib,这应该在他们的文档中

#4


1  

If I understood well from your description, what you have is a signal which is a combination of a sine plus a constant plus some random glitches. Say, like

如果我从你的描述中理解得很好,你所拥有的是一个信号,它是一个正弦加一个常数加上一些随机故障的组合。说,就像

x[n] = A*sin(f*n + phi) + B + N[n]

where N[n] is the "glitch" noise you want to get rid of.

其中N [n]是你要摆脱的“小故障”噪音。

If the glitches are one-sample long, you can remove them using a median filter which has to be bigger than the glitch length. On both sides of the glitch. Glitches of length 1, mean you will have enough with a median of 3 samples of length.

如果毛刺是单样本长,则可以使用中值滤波器去除它们,中值滤波器必须大于毛刺长度。在故障的两边。长度为1的毛刺意味着你将有足够的中位数为3个长度的样本。

y[n] = median3(x[n])

The median is computed so: Take the samples of x you want to filter (x[n-1],x[n],x[n+1]), sort them, and your output is the middle one.

计算中位数是这样的:取你想要过滤的x的样本(x [n-1],x [n],x [n + 1]),对它们进行排序,输出是中间的。

Now that the noise signal is away, get rid of the constant signal. I understand the buffer is of a limited and known length, so you can just compute the mean of the whole buffer. Substract it.

现在噪声信号消失了,摆脱了恒定信号。我知道缓冲区的长度有限且已知,因此您只需计算整个缓冲区的平均值即可。减去它。

Now you have your single sinus signal. You can now compute the fundamental frequency by counting zero crossings. Count the amount of samples above 0 in which the former sample was below 0. The period is the total amount of samples of your buffer divided by this, and the frequency is the oposite (1/x) of the period.

现在你有了单个窦信号。您现在可以通过计算过零点来计算基频。计算前一个样本低于0的样本数量。该时间段是缓冲区样本的总量除以此值,频率是该时间段的对数(1 / x)。

#5


1  

Although I would go with the majority and say that it seems like what you want is an fft solution (fft algorithm is pretty quick), if fft is not the answer for whatever reason you may want to try fitting a sine curve to the data using a fitting program and reading off the fitted frequency.

虽然我会与大多数人一起说,看起来你想要的是一个fft解决方案(fft算法非常快),如果fft不是任何理由的答案,你可能想尝试使用正弦曲线拟合数据一个合适的程序并读取拟合的频率。

Using Fityk, you can load the data, and fit to a*sin(b*x-c) where 2*pi/b will give you the frequency after fitting.

使用Fityk,您可以加载数据,并适合* sin(b * x-c),其中2 * pi / b将在拟合后给出频率。

Fityk can be used from a gui, from a command-line for scripting and has a C++ API so could be included in your programs directly.

Fityk可以从gui,脚本命令行使用,也可以使用C ++ API,因此可以直接包含在程序中。

#6


0  

I googled for "basic fft". Visual Basic FFT Your question screams FFT, but be careful, using FFT without understanding even a little bit about DSP can lead results that you don't understand or don't know where they come from.

我用Google搜索“基本fft”。 Visual Basic FFT你的问题尖叫FFT,但要小心,使用FFT而不了解一点关于DSP可能导致你不理解或不知道它们来自哪里的结果。

#7


0  

get the Frequency Analyzer at http://www.relisoft.com/Freeware/index.htm and run it and look at the code.

在http://www.relisoft.com/Freeware/index.htm上获取频率分析器并运行它并查看代码。

#1


6  

The FFT is probably the best answer, but if you really want to do it by your method, try this:

FFT可能是最好的答案,但如果您真的想通过您的方法来做,请尝试以下方法:

To normalize, first make a histogram to count how many occurrances of each value from 0 to 255. Then throw out X percent of the values from each end with something like:

要进行标准化,首先要制作一个直方图,以计算从0到255的每个值的出现次数。然后从每个端点丢弃X%的值,例如:

for (i=lower=0;i< N*(X/100); lower++)
  i+=count[lower];
//repeat in other direction for upper

Now normalize with

现在正常化

A[i] = 255*(A[i]-lower)/(upper-lower)-128

Throw away results outside the -128..127 range.

抛弃-128..127范围之外的结果。

Now you can count zero crossings. To make sure you are not fooled by noise, you might want to keep track of the slope over the last several points, and only count crossings when the average slope is going the right way.

现在你可以计算过零点。为了确保您不会受到噪音的愚弄,您可能希望跟踪最后几个点的斜率,并且仅在平均斜率正确的情况下计算交叉点。

#2


5  

The standard method to attack this problem is to consider one block of data, hopefully at least twice the actual frequency (taking more data isn't bad, so it's good to overestimate a bit), then take the FFT and guess that the frequency corresponds to the largest number in the resulting FFT spectrum.

解决这个问题的标准方法是考虑一个数据块,希望至少是实际频率的两倍(获取更多数据也不错,所以高估一点是好的),然后采用FFT并猜测频率对应得到的FFT频谱中的最大数字。

By the way, very similar problems have been asked here before - you could search for those answers as well.

顺便说一下,之前已经提出过非常类似的问题 - 您也可以搜索这些答案。

#3


3  

Use the Fourier transform, it's much more noise insensitive than counting zero crossings

使用傅立叶变换,它比计算零交叉更加噪声不敏感

Edit: @WaveyDavey

I found an F# library to do an FFT: From here

我找到了一个F#库来做FFT:从这里开始

As it turns out, the best free implementation that I've found for F# users so far is still the fantastic FFTW library. Their site has a precompiled Windows DLL. I've written minimal bindings that allow thread-safe access to FFTW from F#, with both guru and simple interfaces. Performance is excellent, 32-bit Windows XP Pro is only up to 35% slower than 64-bit Linux.

事实证明,到目前为止,我为F#用户找到的最佳免费实现仍然是非常棒的FFTW库。他们的网站有一个预编译的Windows DLL。我编写了最小的绑定,允许从F#线程安全地访问FFTW,同时使用guru和简单的接口。性能非常出色,32位Windows XP Pro比64位Linux慢了35%。

Now I'm sure you can call F# lib from VB.net, C# etc, that should be in their docs

现在我确定你可以从VB.net,C#等调用F#lib,这应该在他们的文档中

#4


1  

If I understood well from your description, what you have is a signal which is a combination of a sine plus a constant plus some random glitches. Say, like

如果我从你的描述中理解得很好,你所拥有的是一个信号,它是一个正弦加一个常数加上一些随机故障的组合。说,就像

x[n] = A*sin(f*n + phi) + B + N[n]

where N[n] is the "glitch" noise you want to get rid of.

其中N [n]是你要摆脱的“小故障”噪音。

If the glitches are one-sample long, you can remove them using a median filter which has to be bigger than the glitch length. On both sides of the glitch. Glitches of length 1, mean you will have enough with a median of 3 samples of length.

如果毛刺是单样本长,则可以使用中值滤波器去除它们,中值滤波器必须大于毛刺长度。在故障的两边。长度为1的毛刺意味着你将有足够的中位数为3个长度的样本。

y[n] = median3(x[n])

The median is computed so: Take the samples of x you want to filter (x[n-1],x[n],x[n+1]), sort them, and your output is the middle one.

计算中位数是这样的:取你想要过滤的x的样本(x [n-1],x [n],x [n + 1]),对它们进行排序,输出是中间的。

Now that the noise signal is away, get rid of the constant signal. I understand the buffer is of a limited and known length, so you can just compute the mean of the whole buffer. Substract it.

现在噪声信号消失了,摆脱了恒定信号。我知道缓冲区的长度有限且已知,因此您只需计算整个缓冲区的平均值即可。减去它。

Now you have your single sinus signal. You can now compute the fundamental frequency by counting zero crossings. Count the amount of samples above 0 in which the former sample was below 0. The period is the total amount of samples of your buffer divided by this, and the frequency is the oposite (1/x) of the period.

现在你有了单个窦信号。您现在可以通过计算过零点来计算基频。计算前一个样本低于0的样本数量。该时间段是缓冲区样本的总量除以此值,频率是该时间段的对数(1 / x)。

#5


1  

Although I would go with the majority and say that it seems like what you want is an fft solution (fft algorithm is pretty quick), if fft is not the answer for whatever reason you may want to try fitting a sine curve to the data using a fitting program and reading off the fitted frequency.

虽然我会与大多数人一起说,看起来你想要的是一个fft解决方案(fft算法非常快),如果fft不是任何理由的答案,你可能想尝试使用正弦曲线拟合数据一个合适的程序并读取拟合的频率。

Using Fityk, you can load the data, and fit to a*sin(b*x-c) where 2*pi/b will give you the frequency after fitting.

使用Fityk,您可以加载数据,并适合* sin(b * x-c),其中2 * pi / b将在拟合后给出频率。

Fityk can be used from a gui, from a command-line for scripting and has a C++ API so could be included in your programs directly.

Fityk可以从gui,脚本命令行使用,也可以使用C ++ API,因此可以直接包含在程序中。

#6


0  

I googled for "basic fft". Visual Basic FFT Your question screams FFT, but be careful, using FFT without understanding even a little bit about DSP can lead results that you don't understand or don't know where they come from.

我用Google搜索“基本fft”。 Visual Basic FFT你的问题尖叫FFT,但要小心,使用FFT而不了解一点关于DSP可能导致你不理解或不知道它们来自哪里的结果。

#7


0  

get the Frequency Analyzer at http://www.relisoft.com/Freeware/index.htm and run it and look at the code.

在http://www.relisoft.com/Freeware/index.htm上获取频率分析器并运行它并查看代码。