Я работаю над приложением, которое берет два аудиоканала и сравнивает их, чтобы найти разность фаз (задержку). Я наткнулся на это сообщение:
Расчет коэффициента корреляции БПФ
, который ссылается на этот пример кода;
https://dotnetfiddle.net/1nWIgQ
Я получил код, работающий с правильными результатами после перевода его на VB. NET (это язык, с которого я начал лет go в этом приложении).
Проблема, которую я вижу в том, что когда я меняю сигнал, генерируемый случайным шумом, на синусоидальную волну, код дает сумасшедшие несвязанные результаты. Будем благодарны за любые предложения.
Код ниже;
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports AForge.Math 'NuGet Package Aforge.Math module
Imports System.Runtime.InteropServices
Imports System.IO
Public Class Form2
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim c = New Xcorr4_2()
Dim size As Integer = 2048
Dim delay As Double
delay = 2
Dim signal1 = c.GenerateSignal(size)
Dim signal2 = c.GenerateSignal(size, delay)
Dim signal1Complex = c.ToComplexWithPadding(signal1, 2)
Dim fftSignal1 = c.FFT(signal1Complex)
Dim signal2Complex = c.ToComplexWithPadding(signal2, 2)
Dim fftSignal2 = c.FFT(signal2Complex)
Dim cc = c.CorrelationCoefficient(fftSignal1.ToArray(), fftSignal2.ToArray())
MsgBox(cc.Item1) 'correlation coeff
MsgBox(cc.Item2) 'recovered delay
End Sub
End Class
Class Xcorr4_2
Public Function CrossCorrelation(ByVal ffta As Complex(), ByVal fftb As Complex()) As Complex()
Dim conj = ffta.[Select](Function(i) New Complex(i.Re, -i.Im)).ToArray()
conj = conj.Zip(fftb, Function(v1, v2) Complex.Multiply(v1, v2)).ToArray()
FourierTransform.FFT(conj, FourierTransform.Direction.Backward)
Dim rr As Double() = New Double(conj.Length - 1) {}
rr = conj.[Select](Function(i) i.Magnitude).ToArray()
Return conj
End Function
Public Function CorrelationCoefficient(ByVal ffta As Complex(), ByVal fftb As Complex()) As Tuple(Of Double, Integer)
Dim tuble As Tuple(Of Double, Integer)
Dim correlation = CrossCorrelation(ffta, fftb)
Dim seq = correlation.[Select](Function(i) i.Magnitude)
Dim maxCoeff = seq.Max()
Dim maxIndex As Integer = seq.ToList().IndexOf(maxCoeff)
tuble = New Tuple(Of Double, Integer)(maxCoeff, maxIndex)
Return tuble
End Function
Public Function FFT(ByVal signal As Complex()) As Complex()
FourierTransform.FFT(signal, FourierTransform.Direction.Forward)
Return signal
End Function
Public Function IFFT(ByVal signal As Complex()) As Complex()
FourierTransform.FFT(signal, FourierTransform.Direction.Backward)
Return signal
End Function
Public Function ToComplexWithPadding(ByVal sample As Double(), ByVal Optional padding As Integer = 1) As Complex()
Dim logLength As Double = Math.Ceiling(Math.Log(sample.Length * padding, 2.0))
Dim paddedLength As Integer = CInt(Math.Pow(2.0, Math.Min(Math.Max(1.0, logLength), 14.0)))
Dim complex As Complex() = New Complex(paddedLength - 1) {}
Dim samples = sample.ToArray()
Dim i As Integer = 0
While i < sample.Length
complex(i) = New Complex(samples(i), 0)
i += 1
End While
While i < paddedLength
complex(i) = New Complex(0, 0)
i += 1
End While
Return complex
End Function
Public Function GenerateSignal(ByVal size As Integer, ByVal Optional shift As Integer = 0) As Double()
Dim list As List(Of Double) = New List(Of Double)()
Dim generator = New AForge.Math.Random.StandardGenerator()
' Changed original random signal to Sine wave below
For i As Integer = 0 To size - 1
'Dim randomNumber As Double = generator.[Next]()
'list.Add(randomNumber)
list.Add(Math.Sin(2 * Math.PI / 200 * i + shift))
Next
Dim list2 As List(Of Double) = New List(Of Double)()
For i As Integer = 0 To shift - 1
list2.Add(0)
Next
Dim ar = list.ToArray()
For i As Integer = 0 To size - shift - 1
list2.Add(ar(i))
Next
Return list2.ToArray()
End Function
End Class
Ниже приведен вывод исходного кода и модифицированного кода с синусоидальной волной.
Исходный код случайный сигнал
Модифицировано синусоидальными входами