2016-05-12 12 views
0

zurück Ich verwende vDSP_conv, um Autokorrelation durchzuführen. Meistens funktioniert es gut, aber manchmal füllt es das Ausgangs-Array mit NaNs.vDSP_conv gibt gelegentlich NANs

Der Code:

func corr_test() { 
    var pass = 0 

    var x = [Float]() 
    for i in 0..<2000 { 
    x.append(Float(i)) 
    } 

    while true { 
    print("pass \(pass)") 

    let corr = autocorr(x) 
    if corr[1].isNaN { 
     print("!!!") 
    } 
    pass += 1 
    } 
} 

func autocorr(a: [Float]) -> [Float] { 
    let resultLen = a.count * 2 + 1 
    let padding = [Float].init(count: a.count, repeatedValue: 0.0) 
    let a_pad = padding + a + padding 
    var result = [Float].init(count: resultLen, repeatedValue: 0.0) 

    vDSP_conv(a_pad, 1, a_pad, 1, &result, 1, UInt(resultLen), UInt(a_pad.count)) 

    return result 
} 

Der Ausgang:

pass ... 
pass 169 
pass 170 
pass 171 
(lldb) p corr 
([Float]) $R0 = 4001 values { 
    [0] = 2.66466637E+9 
    [1] = NaN 
    [2] = NaN 
    [3] = NaN 
    [4] = NaN 
... 

Ich bin nicht sicher, was hier los ist. Ich denke, dass ich die 0-Padding richtig handle, denn wenn ich es nicht wäre, würde ich nicht 99% der Zeit korrekte Ergebnisse bekommen.

Ideen? Gracias.

+0

Die Dokumente sagen, dass Vektor A "muss mindestens N + P - 1." N ist die Länge des Ausgabevektors und P ist die Länge des Filtervektors, daher ist die Art, wie ich das Array paddle, wahrscheinlich falsch, aber ich bin mir immer noch nicht sicher, was die richtige Methode ist. –

Antwort

0

Ich habe es herausgefunden. Der Schlüssel war dieser Kommentar von https://developer.apple.com/library/mac/samplecode/vDSPExamples/Listings/DemonstrateConvolution_c.html:

// “The signal length is padded a bit. This length is not actually passed to the vDSP_conv routine; it is the number of elements 
// that the signal array must contain. The SignalLength defined below is used to allocate space, and it is the filter length 
// rounded up to a multiple of four elements and added to the result length. The extra elements give the vDSP_conv routine 
// leeway to perform vector-load instructions, which load multiple elements even if they are not all used. If the caller did not 
// guarantee that memory beyond the values used in the signal array were accessible, a memory access violation might result.” 

„ein wenig aufgefüllt.“ Danke für so spezifisch zu sein. Wie auch immer, hier ist das letzte funktionierende Produkt:

func autocorr(a: [Float]) -> [Float] { 
let filterLen = a.count 
let resultLen = filterLen * 2 - 1 
let signalLen = ((filterLen + 3) & 0xFFFFFFFC) + resultLen 

let padding1 = [Float].init(count: a.count - 1, repeatedValue: 0.0) 
let padding2 = [Float].init(count: (signalLen - padding1.count - a.count), repeatedValue: 0.0) 
let signal = padding1 + a + padding2 

var result = [Float].init(count: resultLen, repeatedValue: 0.0) 

vDSP_conv(signal, 1, a, 1, &result, 1, UInt(resultLen), UInt(filterLen)) 

// Remove the first n-1 values which are just mirrored from the end so that [0] always has the autocorrelation. 
result.removeFirst(filterLen - 1) 

return result 
} 

Beachten Sie, dass die Ergebnisse hier nicht normalisiert sind.

Verwandte Themen