我目前正在研究Java和Java的吉他调音器程序 我正在尝试实施谐波产品频谱算法以确定基频。
目前,我制作了一种方法,通过因子 f 对我的频谱进行下采样。</ p>
我现在正试图将所有不同的下采样频谱相乘。 我在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。
我们继续这样做,直到我们填满阵列。
如果一切顺利,我们应该在最后:
我只需要找到最大峰值以找到我的基频。
我唯一的问题是我不知道怎么做倍增.....
如果有人有想法,我会非常感激!
答案 0 :(得分:4)
好的,我有一个实际答案,这就是我解决问题的方法:
首先,我不称之为下采样,而是划分FFT的频率。为此我只使用2个数组:
float findex[1000]; //index of frequencies for harmonic product spectrum
float mindex[1000]; //index of magnitudes for harmonic product spectrum
unsigned int max_findex; //number of elements in findex[] and mindex[]
这是我的初始化: max_findex = 0; for(i = 0; i&lt; 1000; i ++){ mindex [i] = 0.0; }
我正在开发VisualDSP ++中的Analog Devices Sharc EZ开发板,因此我的代码在C中。
我在12kHz的低采样率下使用131072的大FFT。这给了我相当高的每箱0.09Hz的精度。由于高次谐波将更准确,我首先从我的最高分部开始:
//first run with max division (highest accuracy)
for (i = 0; i < new_peak; i++) {
findex[max_findex] = f(peak[i].index) / 9;
mindex[max_findex] = peak[i].magnitude;
if (max_findex < 999) max_findex++;
else xmitUARTmessage("ERROR max_findex\r\n", 100);
}
我在FFT结构中得到了所有峰值,如下所示: peak [] .index是FFT中的bin编号,peak []。magnitude是峰值的大小。 f()函数返回bin的频率。
接下来我会去8师,然后7,等等和1师(实际频率最后)。 对于每个分割的峰值,我查看我的数组,看看此时我是否已经有一个频率。我使用+/- 0.2,我可能会收紧它,但你必须将其调整到你的FFT精度。
char found;
for (u2 = 8; u2 > 0; u2--) {
for (i = 0; i < new_peak; i++) {
tempf = f(peak[i].index) / u2;
found = 0;
for (u = 0; u < max_findex; u++) {
//try to find existing frequency
if (tempf < findex[u] + 0.2 && tempf > findex[u] - 0.2) {
//found existing frequency
mindex[u] *= peak[i].magnitude;
found = 1;
break;
}
} //for u
if (!found) {
//no frequency was found, add new one
findex[max_findex] = tempf;
mindex[max_findex] = peak[i].magnitude;
if (max_findex < 999) max_findex++;
else xmitUARTmessage("ERROR max_findex\r\n", 100);
}
} //for i
} //for u2
就是这样。现在我只打印出我的值并在Excel中按大小排序......
for (i = 0; i < max_findex; i++) {
sprintf(tempstr, "%.2f,%.2f\r\n", findex[i], mindex[i]);
xmitUARTmessage(tempstr, 100);
}
这是一些输出(我只显示前6位): 60.53 1705693250000 60 1558419875000 20 555159950 179.99 264981525 7.5 1317353 8.57 1317353
创建输出的输入音频信号是: 60 Hz方波(基波加奇次谐波) 181.5 Hz正弦波 302.5 Hz正弦波 423.5 Hz正弦波
我正在模拟60 + 60.5 Hz的拍频,基本完全缺失为60.5。这是一个棘手的案例,它有效:)