【发布时间】:2012-05-05 13:00:45
【问题描述】:
我目前正在使用 Java 开发吉他调音器程序,并且 我正在尝试实现谐波乘积频谱算法以确定基频。
目前,我制作了一种方法,可以将我的光谱下采样一个因子 f。
我现在正尝试将所有不同的下采样频谱相乘。 我正在用 java 编码并使用数组。 因此,我有针对已下采样的索引的数组和针对我的频谱的不同值的数组。 我现在正试图将所有不同的数组设置为相同的大小并组织它们的值,以便它们对应于正确的下采样索引。 我在大小和值方面有很多问题....
此外,我正在尝试根据我在纸上的一个示例来实现这个算法......因此我只能用 4 个下采样频谱来实现这个算法,但我怀疑这在我实际使用时是否足够真实的声音信号。
这里是下采样方法的代码:
import org.jfree.ui.RefineryUtilities;
public class SousEchantillonnage {
public static double[] valuesDownSample(double[] tab, int factor){
int N = tab.length;
double[] values = new double[N];
for (int i = 0; i < N; i++){
values[i] = tab[i];
}
int lengthDownSample = N + (facteur - 1) * (N - 1);
double[] valuesDownSample = new double[lengthDownSample];
for (int i = 0; i < N; i++){
valuesDownSample[i] = values[i];
}
for (int i = N; i < lengthDownSample; i ++){
valuesDownSample[i] = 0;
}
return valuesDownSample;
}
public static double[] indexDownSample(double[] tab, int factor){
int N = tab.length;
double[] indexes = new double[N];
for (int i = 0; i < N; i++){
indexes[i] = i;
}
int lengthDownSample = N + (factor - 1) * (N - 1);
double[] indexDownSample = new double [lengthDownSample];
for (int i = 0; i < lengthDownSample; i++){
indexDownSample[i] = i / factor;
}
return indexDownSample;
}
这个方法似乎有效。
到目前为止,这是我的 HPS 算法方法:
public static double[] hps(double[] tab){
int N = tab.length;
int factor2 = 2;
int factor3 = 3;
int factor4 = 4;
int lengthDownSample2 = N/2 + (factor2 - 1) * (N/2 - 1);
int lengthDownSample3 = N/2 + (factor3 - 1) * (N/2 - 1);
int lengthDownSample4 = N/2 + (factor4 - 1) * (N/2 - 1);
// Gives us the spectrogram of the signal tab
double[] spectrogram = new double[N];
spectrogramme = FFT.calculFFT(tab);
// We only need the first values of the spectrogram. The other half is the same.
double[] spectrogramCut = new double[N/2];
for (int i = 0; i < N/2; i++){
spectrogramCut[i] = spectrogram[i];
}
// We create the array that contains the values of spectrogramCut that we downsample by a factor 2
double[] valuesSpect2 = new double [sizeDownSamp2];
valuesSpect2 = SousEchantillonnage.valuesDownSample(spectrogramCut, factor2);
// We create an array of the indexes of spectrogramCut that we downsample by a factor 2
double[] indexSpect2 = new double[sizeDownSamp2];
indexSpect2 = SousEchantillonnage.indexDownSample(spectrogramCut, factor2);
// We create the array that contains the values of spectrogramCut that we downsample by a factor 3
double[] valuesSpect3 = new double [sizeDownSamp3];
valuesSpect3 = SousEchantillonnage.valuesDownSample(spectrogramCut, factor3);
// We create an array of the indexes of spectrogramCut that we downsample by a factor 3
double[] indexSpect3 = new double[sizeDownSamp3];
indexSpect3 = SousEchantillonnage.indexDownSample(spectrogramCut, factor3);;
// We create the array that contains the values of spectrogramCut that we downsample by a factor 4
double[] valuesSpect4 = new double [sizeDownSamp4];
valuesSpect4 = SousEchantillonnage.valuesDownSample(spectrogramCut, factor4);
// We create an array of the indexes of spectrogramCut that we downsample by a factor 4
double[] indexSpect4 = new double[sizeDownSamp4];
indexSpect4 = SousEchantillonnage.indexDownSample(spectrogramCut, factor4);
int sizeIndex = N/2 + 5 * (N/2 - 1); // size of the array that contains all the indexes of the downsamples
// We create this array
double[] indexDowSamp = new double[sizeIndex];
indexDowSamp[0] = 0;
indexDowSamp[1] = 0.25;
indexDowSamp[2] = 0.333;
indexDowSamp[3] = 0.5;
indexDowSamp[4] = 0.666;
indexDowSamp[5] = 0.75;
int q = sizeIndex / 6; // quantity of packets of 6 we can do
int r = sizeIndex%6; // what we are left with.
for (int i = 6; i < q * 6; i += 6){
for (int j = 0; j < 6; j++){
indexDowSamp[i + j] = indexDowSamp[i + j - 6] + 1;
}
}
for (int i = 0; i < r; i++){
indexDowSamp[q * 6 + i] = indexDowSamp[q * 6 + i - 6] + 1;
}
我被困在这里。我想做一个将两个不同长度的数组相乘的方法。
基本上,如您所见,当我对频谱图进行下采样时,我会得到两个数组:
- 具有下采样索引的索引
- 另一个具有下采样后的值。
我想做的是创建一个与indexDownSample:valuesDownSample 大小相同的数组。
例如,我们有indexDownSample[0] = 0。
对于valuesDownSample[0],我想要valuesSpectCut[0] *valuesSpect2[0]*valuesSpect3[0]*valuesSpect4[0] 的乘积,因为所有这些数组都有一个对应于索引0 的值(indexSpectCut[0] = 0,indexSpect2[0] = 0 = indexSpect3[0] = indexSpect4[0])。
对于indexDownSample[1]=0.25,我们注意到只有indexSpect4[1]= indexDownSample[1] = 0.25
然后,valuesDownSample[1] 默认为 0。
我们继续这样,直到我们填满数组。
如果一切顺利,我们应该在最后:
- valuesDownSample 包含产品的不同值
- indexDownSample 包含不同的下采样索引。
我只需要找到最大峰值即可找到我的基频。
我唯一的问题是我不知道如何做乘法.....
如果有人有想法,我将不胜感激!
【问题讨论】:
-
如果您描述了您实际遇到的问题并至少展示了您迄今为止所做的一些事情,这将很有帮助。事实上,现在我们必须猜测该建议什么......
-
为什么是java?!?尝试 c++、fortran 或其他东西!
-
感谢两位的回答。我的项目必须在java中。这不是一个选择……它是强加的。而到目前为止的代码是我为下采样所做的。很抱歉,虽然我的注释将是法语.....