सॉफ्टवेयर में AFSK सिग्नल को कैसे डीमोड्यूलेट करें


14

मैं एक ऑडियो चैनल (स्पीकर / माइक) पर बाइनरी डेटा को एक डिवाइस से दूसरे पर प्रसारित करने की कोशिश कर रहा हूं। मैं पैकेट रेडियो में AFSK (ऑडियो फ्रिक्वेंसी शिफ्ट कींग) का उपयोग करता हूं, और दो फ्रीक्वेंसी और । मैंने रूबी में थोड़ा सा खेला और मेरा पहला कार्यान्वयन केवल एक क्लासिक असंगत डिमोडुलेटर का अनुकरण करता है, जो अब तक ठीक काम करता है।1200 बॉडआर=1200 हर्ट्जरोंपीसी=2200 हर्ट्ज

समस्या यह है, मैं इसे एक मोबाइल प्लेटफॉर्म पर पोर्ट करने की कोशिश कर रहा हूं जहां प्रदर्शन एक चिंता का विषय है और मेरा वर्तमान समाधान बहुत धीमा है। मुझे AFSK को सॉफ्टवेयर में ध्वस्त करने के कई तरीके मिले हैं:

  • स्लाइडिंग DFT (FFT)
  • स्लाइडिंग Görtzel फ़िल्टर
  • चरण बंद लूप
  • जीबरा क्रोससिंग

जाने का रास्ता क्या होगा? चुनने के लिए बहुत सारे विकल्प हैं। मुझे यकीन है कि और भी विकल्प उपलब्ध हैं। शायद ऊपर मौजूद लोगों के नाम से भी बेहतर उपाय मौजूद हैं? क्या मेरे लिए भी कोई कोड उदाहरण है? मैं चिंतित हूं

  • प्रदर्शन (मोबाइल प्लेटफ़ॉर्म पर चलना चाहिए, iOS या Android डिवाइस कहें)
  • स्थिरता (कुछ शोर को संभालने में सक्षम होना चाहिए)

किसी भी सुझाव और संकेत बहुत सराहना की है!


3
मुझे लगता है कि आप अपने द्वारा लक्षित मोबाइल उपकरणों की कम क्षमता को बेच रहे हैं। याद रखें कि आधुनिक उपकरण 1 गीगाहर्ट्ज़ से अधिक की घड़ी की गति वाले मल्टीकोर प्रोसेसर हैं। FSK डेमोडुलेटर के साथ <10 ksps सिग्नल को संसाधित करना प्रदर्शन समस्या नहीं होनी चाहिए। लेकिन ऐसा कोई कारण नहीं होना चाहिए कि आपके मौजूदा दृष्टिकोण (जो मुझे मार्क / स्पेस फिल्टरिंग की तरह लगता है) को आधुनिक मोबाइल प्लेटफॉर्म पर वास्तविक समय में चलाने में सक्षम नहीं होना चाहिए। यहां तक ​​कि अधिक परिष्कृत पीएलएल-आधारित दृष्टिकोण आपके प्रसंस्करण लिफाफे में आराम से फिट होना चाहिए। मैं आपके मौजूदा कोड को थोड़ा प्रोफाइल करूंगा।
जेसन आर

जवाबों:


9

मुझे लगता है कि आप चरण-बंद लूप के साथ डेमोडुलेटर बिट-त्रुटि दर (बीईआर) के संदर्भ में सर्वश्रेष्ठ प्रदर्शन प्राप्त कर सकते हैं। हालांकि, आपको तेज़ होने की ज़रूरत है। मुझे लगता है कि एक तेज एल्गोरिथ्म के लिए आपका सबसे अच्छा दांव जो अभी भी यथोचित प्रदर्शन करता है वह है जीरो क्रॉसिंग।

एक साइड नोट पर, मैं सुझाव देना चाहूंगा कि आप 2200 हर्ट्ज को 2400 हर्ट्ज में बदल दें। 1200/2200 हर्ट्ज योजना के एक भोले-भाले क्रियान्वयन से छूट मिल जाएगी, जैसा कि नीचे दिए गए कथानक में दो तिहाई देखा जाता है, जहां 2200 हर्ट्ज से 1200 हर्ट्ज तक संक्रमण होता है।

1200 हर्ट्ज और 2200 हर्ट्ज

आपके द्वारा उपयोग किए जा रहे बैंडविड्थ को कम करने के लिए और चरण को निरंतर बनाने के लिए आवश्यक सिग्नल को विकृत करने वाली असंगतताओं से बचें। यहां तक ​​कि अगर आप ट्रांसमीटर चरण को निरंतर बनाते हैं, हालांकि, अभी भी यह मुद्दा होगा कि 2200 हर्ट्ज प्रतीकों में हमेशा अलग-अलग चरणों के कारण शून्य क्रॉसिंग की समान संख्या नहीं होगी। आमतौर पर उनके पास चार शून्य क्रॉसिंग होंगे, लेकिन कभी-कभी उनके पास तीन होंगे। दूसरी ओर 1200 हर्ट्ज प्रतीकों में हमेशा दो शून्य क्रॉसिंग होंगे क्योंकि बॉड दर एफएसके आवृत्ति में समान रूप से विभाजित होती है।

आप 2200 Hz से 2400 Hz बदलकर इन दोनों समस्याओं को हल कर सकते हैं। फिर प्रतीक हमेशा 0 डिग्री पर शुरू और समाप्त होंगे (इस प्रकार स्वचालित रूप से उन्हें लगातार चरण बनाते हैं), और उनके पास हमेशा शून्य क्रॉसिंग की संख्या होगी- दो और चार।

1200 हर्ट्ज और 2400 हर्ट्ज


हे जिम, आपके विस्तृत उत्तर के लिए धन्यवाद! मेरा मॉड्यूलेटर वास्तव में सीपीएफएसके करता है, इसलिए असंतोष एक मुद्दा नहीं है। मैंने जानबूझकर 1200 और 2200 हर्ट्ज को चुना क्योंकि हार्मोनिक्स 1200 के गुणकों के साथ ओवरलैप नहीं करता है। क्या मैं यहां गलत हूं? पीएलएल बहुत अच्छा लगता है, लेकिन मुझे वास्तव में पता नहीं है कि उन्हें कैसे लागू किया जाए। क्या आप सॉफ़्टवेयर PLL के बारे में कोई अच्छा स्रोत जानते हैं?
पैट्रिक ऑसिटी

@ पैट्रिक नं, आप सही हैं कि 1200 और 2400 हर्ट्ज के ओवरलैपिंग हार्मोनिक्स होंगे। शून्य-क्रॉसिंग के संदर्भ में, हालांकि, मुझे नहीं लगता है कि हार्मोनिक्स मामला है। और नहीं, मुझे डर है कि मुझे PLL के बारे में एक अच्छे ऑनलाइन स्रोत का पता नहीं है।
जिम क्ले

यह सही नहीं है। एएफएसके 1200 बेल 202 का अनुसरण करता है, और यह कहता है कि टोन 1200 और 2200 होना चाहिए। ट्रांसमीटर पक्ष में कभी नहीं होना चाहिए। ओपन सोर्स AFSK 1200 मॉड्यूलेटर की जाँच करें, हर टोन के लिए एक चरण वृद्धि को ट्रैक करके मॉड्यूलेशन किया जाता है: यदि टोन == कम है तो last_phase + = ph_low और last_phase + = ph_high endif; next_sample = sin (last_phase);
vz0

5

मैंने AFSK (बेल 202 मानक) के लिए एक डिकोडर का उपयोग 1200 Hz और 2200 Hz के लिए सहसंबंध रिसीवर का उपयोग करके किया, बहुत अच्छे परिणाम के साथ।

चूंकि एक प्रतीक के दौरान संकेत का चरण अज्ञात है, एक समाधान जटिल डोमेन में काम करना है: वास्तविक साइनसोइड द्वारा गुणा करने के बजाय, जटिल घातीय द्वारा गुणा करें। इसका अर्थ है कि और स्वतंत्र रूप से गुणा करना , फिर प्रत्येक को एकीकृत करना, और पूर्ण (वर्ग) मान की गणना करना।पापक्योंकि

परिणामस्वरूप आयाम सिग्नल चरण से काफी स्वतंत्र है, और आउटपुट एसएनआर बहुत अच्छा है।


यह वही है जो मैंने पहले भी आजमाया है और जिसे मैंने o क्लासिक इनकॉर्पोरेट डिमोडुलेटर ’कहा है। शायद मेरा कार्यान्वयन गलत है, लेकिन मुझे डर है कि यह धीमी गति से प्रसंस्करण के कारण बफर ओवरफ्लो से ग्रस्त है। फिर भी धन्यवाद!
पैट्रिक ऑसिटी

0

RTTY 45.45 बॉड के मामले में, आपके पास ऐसे प्रतीक भी होंगे जो पूर्णांक संख्या के नमूने नहीं हैं, इसलिए आपको एक फ़ंक्शन की आवश्यकता होती है जिसे प्रत्येक नमूना कहा जा सकता है और फिर उस प्रतीक के समाप्त होने पर इसके वापसी मूल्य में संकेत दे सकता है। और आपको एक चरण संचायक की आवश्यकता होती है, जो साइन लहर के चरण में जहां पर चल रहा है, वहां चल रहा है।

उन प्रतीकों को भेजने के लिए जिनकी लंबाई पूर्णांक दर से अधिक नहीं है, जिन्हें आपको इस फ़ंक्शन की आवश्यकता है ...

int millisecondTimer(double milliseconds, double samplerate, int resettime)
{

    static int fracsample=0;
    static int counter=0;
    static int retvalue=0;
    static int first=1;
    static double oldmilliseconds=1.0;
    static int whole_samples=0;
    static int samerror=32768;
    if(resettime==1)
    {
        samerror=0;
        counter=0;
        retvalue=1;
        first=1;
    }
    if(first==1 || milliseconds !=oldmilliseconds)
    {
        double samplesneeded=1;
        double wholesamples=0;
        samplesneeded=(samplerate) * (milliseconds /1000.0);
        samerror=(modf(samplesneeded, &wholesamples)) * 32768.0;
        whole_samples=wholesamples;
        first=0;
    }

    if(counter<=whole_samples)
    {
        retvalue=2;
        counter++;
    }
    else
    {
        counter-=whole_samples;
        retvalue=1;
        fracsample+=samerror;
        oldmilliseconds=milliseconds;
        if(fracsample>=32768)
        {
            fracsample-=32768;
            counter--;
        }

    }
    return retvalue;
}

इसका उपयोग करने के लिए, साइन लहर के अगले नमूने को उत्पन्न करें और इस फ़ंक्शन को कॉल करें, फिर जांचें कि क्या वापसी का मूल्य दो के बराबर नहीं है। यदि यह दो के बराबर नहीं है, तो अगले प्रतीक पर आगे बढ़ें और तय करें कि क्या आप अंतरिक्ष का निशान भेज रहे हैं, फिर इस फ़ंक्शन को कोड के ब्लॉक के अंदर फिर से कॉल करें जो तब निष्पादित होता है जब आपको पता चला कि वापसी मूल्य दो के बराबर नहीं है।

और यहां रॉकबॉक्स फर्मवेयर से चरण संचयक है, आयाम में बदलाव की अनुमति देने के लिए (पूर्ण मात्रा 32767 है, चरण पूर्ण मात्रा में 180 डिग्री बाहर -32768 है)।

signed short lerpsin(float frequency,signed short amplitude,unsigned long samplerate)
{
    /* 128 sixteen bit sine samples + guard point */
    static unsigned long phase=0;
    unsigned int pos =0;
    unsigned short frac=0;
    static unsigned long step=0;
    static float old_frequency=0;
    signed short diff=0;
    static const signed short sinetab[129] =
    {
        0,   1607,   3211,   4807,   6392,   7961,   9511,  11038,
        12539,  14009,  15446,  16845,  18204,  19519,  20787,  22004,
        23169,  24278,  25329,  26318,  27244,  28105,  28897,  29621,
        30272,  30851,  31356,  31785,  32137,  32412,  32609,  32727,
        32767,  32727,  32609,  32412,  32137,  31785,  31356,  30851,
        30272,  29621,  28897,  28105,  27244,  26318,  25329,  24278,
        23169,  22004,  20787,  19519,  18204,  16845,  15446,  14009,
        12539,  11038,   9511,   7961,   6392,   4807,   3211,   1607,
        0,  -1607,  -3211,  -4807,  -6392,  -7961,  -9511, -11038,
        -12539, -14009, -15446, -16845, -18204, -19519, -20787, -22004,
        -23169, -24278, -25329, -26318, -27244, -28105, -28897, -29621,
        -30272, -30851, -31356, -31785, -32137, -32412, -32609, -32727,
        -32767, -32727, -32609, -32412, -32137, -31785, -31356, -30851,
        -30272, -29621, -28897, -28105, -27244, -26318, -25329, -24278,
        -23169, -22004, -20787, -19519, -18204, -16845, -15446, -14009,
        -12539, -11038, -9511,   -7961,  -6392,  -4807,  -3211,  -1607,
        0,
    };
    if(frequency!=old_frequency)
    {
        step = 0x100000000ull*frequency / samplerate;
    }
    phase+=step;
    pos = phase >> 25;
    frac = (phase & 0x01ffffff) >> 9;
    diff = sinetab[pos + 1] - sinetab[pos];
    old_frequency=frequency;
    return ((-((sinetab[pos] + (frac*diff >> 16)))) * amplitude) >> 15;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.