Кросс-корреляция в. NET - PullRequest
       2

Кросс-корреляция в. NET

0 голосов
/ 26 апреля 2020

Я работаю над приложением, которое берет два аудиоканала и сравнивает их, чтобы найти разность фаз (задержку). Я наткнулся на это сообщение:

Расчет коэффициента корреляции БПФ

, который ссылается на этот пример кода;

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

Ниже приведен вывод исходного кода и модифицированного кода с синусоидальной волной.

Исходный код случайный сигнал

Модифицировано синусоидальными входами

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...