2015-12-16 12 views
5

मैं एक फ़िल्टरबैंक पोर्ट कर रहा हूं जो वर्तमान में एंड्रॉइड के लिए ऐप्पल-विशिष्ट (एक्सीलरेट) वीडीएसपी फ़ंक्शन vDSP_deq22 का उपयोग करता है (जहां त्वरण उपलब्ध नहीं है)। फ़िल्टरबैंक बैंडपास फिल्टर का एक सेट है जो प्रत्येक अपने संबंधित बैंड के लिए आरएमएस परिमाण को वापस करता है। वर्तमान में कोड (ObjectiveC++, NVDSP से रूपांतरित) इस तरह दिखता है:बाइकैड आईआईआर फ़िल्टर के लिए वीडीएसपी_डेक 22 को हाथ से

- (float) filterContiguousData: (float *)data numFrames:(UInt32)numFrames channel:(UInt32)channel { 

    // Init float to store RMS volume 
    float rmsVolume = 0.0f; 

    // Provide buffer for processing 
    float tInputBuffer[numFrames + 2]; 
    float tOutputBuffer[numFrames + 2]; 

    // Copy the two frames we stored into the start of the inputBuffer, filling the rest with the current buffer data 
    memcpy(tInputBuffer, gInputKeepBuffer[channel], 2 * sizeof(float)); 
    memcpy(tOutputBuffer, gOutputKeepBuffer[channel], 2 * sizeof(float)); 
    memcpy(&(tInputBuffer[2]), data, numFrames * sizeof(float)); 

    // Do the processing 
    vDSP_deq22(tInputBuffer, 1, coefficients, tOutputBuffer, 1, numFrames); 
    vDSP_rmsqv(tOutputBuffer, 1, &rmsVolume, numFrames); 

    // Copy the last two data points of each array to be put at the start of the next buffer. 
    memcpy(gInputKeepBuffer[channel], &(tInputBuffer[numFrames]), 2 * sizeof(float)); 
    memcpy(gOutputKeepBuffer[channel], &(tOutputBuffer[numFrames]), 2 * sizeof(float)); 

    return rmsVolume; 
} 

देखा here के रूप में, deq22 एक पुनरावर्ती समारोह के माध्यम से दिए गए इनपुट वेक्टर पर एक biquad फिल्टर लागू करता है। vDSP_deq22

  • एक =:: यह डॉक्स से समारोह का वर्णन है एकल परिशुद्धता असली इनपुट वेक्टर
  • आइए =: 5 एकल परिशुद्धता: ए
  • बी = के लिए स्ट्राइड इनपुट (फ़िल्टर गुणांक), 1 के साथ 1.
  • सी = एकल-सटीक वास्तविक आउटपुट वेक्टर।
  • आईसी =: सी
  • एन = उत्पादन के लिए नए आउटपुट तत्वों की संख्या।

    // N is fixed on init to be the same size as buffer.count, below 
    // 'input' and 'output' are initialised with (N+2) length and filled with 0s 
    
    func getFilteredRMSMagnitudeFromBuffer(var buffer: [Float]) -> Float { 
        let inputStride = 1 // hardcoded for now 
        let outputStride = 1 
    
        input[0] = input[N] 
        input[1] = input[N+1] 
        output[0] = output[N] 
        output[1] = output[N+1] 
    
        // copy the current buffer into input 
        input[2 ... N+1] = buffer[0 ..< N] 
    
        // Not sure if this is neccessary, just here to duplicate NVDSP behaviour: 
        output[2 ... N+1] = [Float](count: N, repeatedValue: 0)[0 ..< N] 
    
        // Again duplicating NVDSP behaviour, can probably just start at 0: 
        var sumOfSquares = (input[0] * input[0]) + (input[1] * input[1]) 
    
        for n in (2 ... N+1) { 
         let sumG = (0...2).reduce(Float(0)) { total, p in 
          return total + input[(n - p) * inputStride] * coefficients[p] 
         } 
    
         let sumH = (3...4).reduce(Float(0)) { total, p in 
          return total + output[(n - p + 2) * outputStride] * coefficients[p] 
         } 
    
         let filteredFrame = sumG - sumH 
         output[n] = filteredFrame 
         sumOfSquares = filteredFrame * filteredFrame 
        } 
    
        let meanSquare = sumOfSquares/Float(N + 2) // we added 2 values by hand, before the loop 
        let rootMeanSquare = sqrt(meanSquare) 
        return rootMeanSquare 
    } 
    

    फिल्टर एक अलग परिमाण उत्पादन हालांकि deq22 करने देता है:

यह वही है मैं अब तक (यह codebase के बाकी है कि मैं पहले से ही Android पर चल चुके हैं, स्विफ्ट में है) है , और इसमें एक चक्रीय घुमावदार सर्कुलर 'शोर' लगता है (एक स्थिर इनपुट स्वर के साथ, आवृत्ति की परिमाण ऊपर और नीचे पंप)।

मैंने यह सुनिश्चित करने के लिए जांच की है कि गुणांक सरणी प्रत्येक कार्यान्वयन के बीच समान हैं। प्रत्येक फ़िल्टर वास्तव में "काम" लगता है कि यह सही आवृत्ति (और केवल उस आवृत्ति) को चुनता है, यह सिर्फ यह पंपिंग है, और आरएमएस परिमाण आउटपुट वीडीएसपी की तुलना में बहुत शांत है, अक्सर परिमाण के आदेश:

Naive | vDSP 
3.24305e-06 0.000108608 
1.57104e-06 5.53645e-05 
1.96445e-06 4.33506e-05 
2.05422e-06 2.09781e-05 
1.44778e-06 1.8729e-05 
4.28997e-07 2.72648e-05 

क्या कोई मेरे तर्क के साथ कोई समस्या देख सकता है?

संपादित करें: यहां निरंतर 440 हर्ट्ज टोन के साथ परिणाम का एक gif वीडियो है। विभिन्न हरे रंग के सलाखों में व्यक्तिगत फ़िल्टर बैंड होते हैं। तीसरा बैंड (यहां दिखाया गया) एक 440 हर्ट्ज तक ट्यून किया गया है।

Pumping

NVDSP संस्करण सिर्फ एक निरंतर (गैर अस्थिर) परिमाण इनपुट मात्रा के लिए आनुपातिक पढ़ना, अपेक्षा के अनुरूप पता चलता है।

उत्तर

4

ठीक है, लाइन sumOfSquares = filteredFrame * filteredFrame+= होना चाहिए, असाइनमेंट नहीं। तो केवल अंतिम फ्रेम की गणना की जा रही थी, बहुत कुछ बताती है;)

अगर आप स्विफ्ट में कुछ बिकैड फ़िल्टरिंग करना चाहते हैं तो इसका उपयोग करने के लिए स्वतंत्र महसूस करें। इसके पहले एनवीडीएसपी जैसे एमआईटी लाइसेंस।

+0

यह कमाल है! :) – bartolsthoorn

+1

@ बार्टोलस्टोर्न धन्यवाद :) देखें [यहां] (https: // माध्यम।com/@ ephemer/why-we-put-an-app-in-the -roid-play-store-use-swift-96ac87c88dfc) यदि आप रुचि रखते हैं कि हम – ephemer

+1

महान कहानी और एनवीडीएसपी के लिए धन्यवाद क्यों करते हैं हेहे का जिक्र करें;) वैसे, 2013 में मैंने एनवीडीएसपी बनाने के संघर्ष के बारे में स्वयं को एक छोटा सा नोट लिखा था (आपको यह सही मिला, Google अनुवाद का उपयोग करने के लिए मुझे बहुत कम दस्तावेज था): https://medium.com/ @ Bartolsthoorn/बहादुर-ऑडियो-फिल्टर -1964521efbc7 # .vdsj4j83m – bartolsthoorn

संबंधित मुद्दे