我正在尝试在 Android 上的录音中检测我的啁啾回声,似乎互相关是找到两个信号的 FFT 相似位置的最合适方法,从那里我可以识别互相关数组中的峰值将对应于距离。
据我了解,我提出了以下互相关函数。这个对吗?我不确定是否在开头添加零并重新开始一些元素?
public double[] xcorr1(double[] recording, double[] chirp) {
double[] recordingZeroPadded = new double[recording.length + chirp.length];
for (int i = recording.length; i < recording.length + chirp.length; ++i)
recordingZeroPadded[i] = 0;
for (int i = 0; i < recording.length; ++i)
recordingZeroPadded[i] = recording[i];
double[] result = new double[recording.length + chirp.length - 1];
for (int offset = 0; offset < recordingZeroPadded.length - chirp.length; ++offset)
for (int i = 0; i < chirp.length; ++i)
result[offset] += chirp[i] * recordingZeroPadded[offset + i];
return result;
}
次要问题:
根据这个答案,也可以这样计算
corr(a, b) = ifft(fft(a_and_zeros) * fft(b_and_zeros[reversed]))
我根本不明白,但似乎很容易实现。那就是说我失败了(假设我的xcorr1是正确的)。我觉得我完全误解了这一点?
public double[] xcorr2(double[] recording, double[] chirp) {
// assume same length arguments for now
DoubleFFT_1D fft = new DoubleFFT_1D(recording.length);
fft.realForward(recording);
reverse(chirp);
fft.realForward(chirp);
double[] result = new double[recording.length];
for (int i = 0; i < result.length; ++i)
result [i] = recording[i] * chirp[i];
fft.realInverse(result, true);
return result;
}
假设我两个都工作了,考虑到数组将包含几千个元素,哪个函数最合适?
编辑:顺便说一句,我已经尝试在 FFT 版本的两个数组的两端添加零。
在 SleuthEye 的回应后编辑:
您能否验证一下,因为我正在处理“实际”数据,所以我只需要通过进行真正的转换来完成一半的计算(实际部分)吗?
从您的代码中,看起来 REAL 转换返回的数组中的奇数元素是虚构的。这里发生了什么?
我如何从实数数组变为复数?或者这是转换的目的吗?将实数移入复数域?(但实数只是复数的一个子集,所以它们不是已经在这个域中了吗?)
如果 realForward 实际上返回的是虚数/复数,它与 complexForward 有何不同?我如何解释结果?复数的大小?
对于我对变换缺乏了解,我深表歉意,我到目前为止才研究过傅立叶级数。
感谢您的代码。这是“我的”工作实现:
public double[] xcorr2(double[] recording, double[] chirp) {
// pad to power of 2 for optimisation
int y = 1;
while (Math.pow(2,y) < recording.length + chirp.length)
++y;
int paddedLength = (int)Math.pow(2,y);
double[] paddedRecording = new double[paddedLength];
double[] paddedChirp = new double[paddedLength];
for (int i = 0; i < recording.length; ++i)
paddedRecording[i] = recording[i];
for (int i = recording.length; i < paddedLength; ++i)
paddedRecording[i] = 0;
for (int i = 0; i < chirp.length; ++i)
paddedChirp[i] = chirp[i];
for (int i = chirp.length; i < paddedLength; ++i)
paddedChirp[i] = 0;
reverse(chirp);
DoubleFFT_1D fft = new DoubleFFT_1D(paddedLength);
fft.realForward(paddedRecording);
fft.realForward(paddedChirp);
double[] result = new double[paddedLength];
result[0] = paddedRecording[0] * paddedChirp[0]; // value at f=0Hz is real-valued
result[1] = paddedRecording[1] * paddedChirp[1]; // value at f=fs/2 is real-valued and packed at index 1
for (int i = 1; i < result.length / 2; ++i) {
double a = paddedRecording[2*i];
double b = paddedRecording[2*i + 1];
double c = paddedChirp[2*i];
double d = paddedChirp[2*i + 1];
// (a+b*j)*(c-d*j) = (a*c+b*d) + (b*c-a*d)*j
result[2*i] = a*c + b*d;
result[2*i + 1] = b*c - a*d;
}
fft.realInverse(result, true);
// discard trailing zeros
double[] result2 = new double[recording.length + chirp.length - 1];
for (int i = 0; i < result2.length; ++i)
result2[i] = result[i];
return result2;
}
然而,直到每个大约 5000 个元素,xcorr1 似乎更快。我是否在做任何特别慢的事情(也许是不断“更新”内存——也许我应该转换为 ArrayList)?或者我生成数组来测试它们的任意方式?或者我应该做共轭而不是逆转它?也就是说,性能并不是真正的问题,因此除非有明显的东西,否则您无需费心指出优化。