วิธี demodulate สัญญาณ AFSK ในซอฟต์แวร์


14

ฉันกำลังพยายามส่งข้อมูลไบนารีจากอุปกรณ์หนึ่งไปยังอีกอุปกรณ์หนึ่งผ่านช่องสัญญาณเสียง (ลำโพง / ไมโครโฟน) ผมใช้ AFSK (เสียงความถี่กดปุ่ม Shift Keying) เช่นเดียวกับใน Packet Radio กับและสองความถี่และ{} ฉันเล่น Ruby ไปสักหน่อยและการติดตั้งครั้งแรกของฉันก็เลียนแบบ demodulator แบบไม่ต่อเนื่องแบบคลาสสิคซึ่งทำงานได้ดีจนถึงตอนนี้1200 บอดม.aRk=1200 เฮิร์ตซ์sพีaอี=2200 เฮิร์ตซ์

ปัญหาคือฉันพยายามที่จะพอร์ตนี้ไปยังแพลตฟอร์มมือถือที่มีประสิทธิภาพเป็นกังวลและวิธีแก้ปัญหาปัจจุบันของฉันช้าเกินไป ฉันพบวิธีมากมายในการ demodulate AFSK ในซอฟต์แวร์:

  • เลื่อน DFT (FFT)
  • ตัวเลื่อนGörtzel
  • เฟสล็อกลูป
  • การข้ามเป็นศูนย์

จะไปทางไหนดี? มีตัวเลือกมากมายให้เลือก ฉันแน่ใจว่ามีตัวเลือกมากขึ้น อาจมีวิธีแก้ปัญหาที่ดีกว่าโซลูชันที่ฉันตั้งไว้ข้างต้น มีใครบางคนมีตัวอย่างรหัสสำหรับฉันหรือไม่ ฉันเป็นห่วง

  • ประสิทธิภาพ (ควรเรียกใช้บนแพลตฟอร์มมือถือพูดอุปกรณ์ iOS หรือ Android)
  • ความเสถียร (ควรจะสามารถจัดการกับเสียงรบกวน)

ข้อเสนอแนะและคำแนะนำใด ๆ ที่ชื่นชมอย่างมาก!


3
ฉันคิดว่าคุณน่าจะขายความสามารถของอุปกรณ์มือถือที่คุณกำหนดเป้าหมายสั้น ๆ โปรดจำไว้ว่าอุปกรณ์ที่ทันสมัยเป็นตัวประมวลผลแบบมัลติคอร์ที่มีความเร็วสัญญาณนาฬิกาเกิน 1 GHz การประมวลผลสัญญาณ <10 ksps ด้วย demodulator FSK ไม่ควรนำเสนอปัญหาด้านประสิทธิภาพ แต่ไม่ควรมีเหตุผลใด ๆ ว่าทำไมวิธีการที่มีอยู่ของคุณ (ซึ่งฟังดูเหมือนฉัน / การกรองด้วยเครื่องหมาย / ช่องว่าง) ไม่ควรที่จะทำงานแบบเรียลไทม์บนแพลตฟอร์มมือถือที่ทันสมัย แม้แต่วิธีที่ใช้ PLL ที่ซับซ้อนยิ่งขึ้นก็ควรจะพอดีกับซองจดหมายในการประมวลผลของคุณ ฉันจะโปรไฟล์รหัสที่มีอยู่ของคุณเล็กน้อย
Jason R

1
มีลักษณะที่เหมืองและการเรียนการสอน DSP ผ่านกรณีศึกษาการปฏิบัติของโมเด็ม
Alexey Frunze

คำตอบ:


9

ฉันคิดว่าคุณจะได้รับประสิทธิภาพที่ดีที่สุดในแง่ของอัตราข้อผิดพลาดบิต demodulator (BER) ด้วยการวนลูปเฟสล็อค แม้ว่าคุณจะต้องรวดเร็ว ฉันคิดว่าทางออกที่ดีที่สุดของคุณสำหรับอัลกอริทึมที่รวดเร็วซึ่งยังทำงานได้ดีพอสมควรคือการข้ามศูนย์

ในหมายเหตุด้านข้างฉันอยากจะแนะนำให้คุณเปลี่ยน 2200 Hz เป็น 2400 Hz การดำเนินการตามแผนไร้เดียงสาของ 1200/2200 Hz จะทำให้เกิดความไม่ต่อเนื่องดังที่เห็นประมาณสองในสามของพล็อตด้านล่าง

1200 Hz และ 2200 Hz

เพื่อลดแบนด์วิดท์ที่คุณใช้และหลีกเลี่ยงความไม่ต่อเนื่องที่จะบิดเบือนสัญญาณคุณจะต้องทำให้เฟสต่อเนื่อง แม้ว่าคุณจะทำให้เฟสของตัวส่งสัญญาณต่อเนื่อง แต่ก็ยังคงมีปัญหาที่สัญลักษณ์ 2200 Hz นั้นจะไม่ได้มีจำนวนการข้ามศูนย์เท่ากับเท่ากันเสมอไปเนื่องจากเฟสที่ต่างกัน โดยปกติแล้วพวกเขาจะมีสี่ศูนย์ข้าม แต่บางครั้งพวกเขาจะมีสาม สัญลักษณ์ 1200 Hz ในอีกด้านหนึ่งจะมีการข้ามศูนย์สองครั้งเสมอเนื่องจากอัตราการส่งข้อมูลแบ่งเท่า ๆ กันตามความถี่ FSK

คุณสามารถแก้ไขปัญหาทั้งสองนี้ได้โดยเปลี่ยน 2200 Hz เป็น 2400 Hz จากนั้นสัญลักษณ์จะเริ่มต้นและสิ้นสุดที่ 0 องศา (ซึ่งจะทำให้พวกเขาเฟสต่อเนื่องโดยอัตโนมัติ) และพวกเขาจะมีจำนวนข้ามศูนย์เท่ากัน - สองและสี่

1200 Hz และ 2400 Hz


เฮ้จิมขอบคุณสำหรับคำตอบอย่างละเอียด! โมเดอเรเตอร์ของฉันใช้ CPFSK จริง ๆ แล้วดังนั้นความไม่ต่อเนื่องจึงไม่มีปัญหา ฉันจงใจเลือก 1200 และ 2200 Hz เพราะฮาร์มอนิกไม่ทับซ้อนกันเท่า ๆ กับทวีคูณของ 1200 หรือฉันผิดที่นี่? PLLs ฟังดูดี แต่ฉันไม่มีความคิดเลยว่าจะนำไปใช้อย่างไร คุณรู้จักแหล่งข้อมูลที่ดีเกี่ยวกับซอฟต์แวร์ PLL หรือไม่
Patrick Oscity

@ แพทริกไม่คุณถูกต้องที่ 1200 และ 2400 เฮิร์ตซ์จะมีการประสานเสียงที่ทับซ้อนกัน ในบริบทของการข้ามศูนย์ แต่ฉันไม่คิดว่าเรื่องความสามัคคี และไม่ฉันกลัวว่าฉันไม่รู้แหล่งข้อมูลออนไลน์ที่ดีเกี่ยวกับ PLL
Jim Clay

สิ่งนี้ไม่ถูกต้อง AFSK 1200 ติดตาม Bell 202 และบอกว่าเสียงควรเป็น 1200 และ 2200 ความไม่ต่อเนื่องไม่ควรเกิดขึ้นในฝั่งเครื่องส่งสัญญาณ ลองดูโอเพ่นซอร์ส AFSK 1200 โมดูเลเตอร์การปรับจะทำโดยติดตามการเพิ่มเฟสสำหรับทุกโทนเสียง: ถ้า tone == LOW แล้ว last_phase + = ph_low อื่น last_phase + = ph_high endif; next_sample = sin (last_phase);
vz0

5

ฉันสร้างตัวถอดรหัสสำหรับ AFSK (มาตรฐาน Bell 202) โดยใช้ตัวรับความสัมพันธ์สำหรับ 1200 Hz และ 2200 Hz ด้วยผลลัพธ์ที่ดีมาก

บาปcos

แอมพลิจูดที่เกิดขึ้นค่อนข้างเป็นอิสระจากเฟสสัญญาณและเอาต์พุต SNR นั้นดีมาก


ตรงนี้เป็นสิ่งที่ฉันเคยลองมาก่อนและสิ่งที่ฉันเรียกว่า "demodulator ไม่ต่อเนื่องแบบคลาสสิก" บางทีการใช้งานของฉันอาจผิดพลาด แต่ฉันเกรงว่าจะเกิดปัญหาจากบัฟเฟอร์ล้นเนื่องจากการประมวลผลช้า ขอขอบคุณ!
Patrick Oscity

0

ในกรณีของ RTTY 45.45 baud คุณจะมีสัญลักษณ์ที่ไม่ใช่จำนวนเต็มตัวอย่างดังนั้นคุณต้องใช้ฟังก์ชันที่สามารถเรียกแต่ละตัวอย่างแล้วส่งสัญญาณในค่าส่งคืนเมื่อสัญลักษณ์นั้นสิ้นสุด และคุณจำเป็นต้องมีแอคติมูเลเตอร์แบบเฟสซึ่งจะทำงานต่อเนื่องซึ่งเฟสของคลื่นไซน์นั้น

ในการส่งสัญลักษณ์ที่มีความยาวไม่ใช่จำนวนเต็มคูณอัตราตัวอย่างคุณต้องใช้ฟังก์ชันนี้ ...

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;
}

หากต้องการใช้ให้สร้างตัวอย่างคลื่นไซน์ถัดไปและเรียกใช้ฟังก์ชันนี้จากนั้นตรวจสอบว่าค่าส่งคืนไม่เท่ากับสอง หากมันไม่เท่ากับสองให้เลื่อนไปที่สัญลักษณ์ถัดไปและตัดสินใจว่าคุณกำลังส่งเครื่องหมายของช่องว่างหรือไม่จากนั้นเรียกใช้ฟังก์ชันนี้อีกครั้งภายในบล็อกของรหัสซึ่งดำเนินการเมื่อคุณพบว่าค่าส่งคืนไม่เท่ากับสอง

และนี่คือตัวสะสมเฟสจากเฟิร์มแวร์ Rockbox โดยมีการเปลี่ยนแปลงเพื่ออนุญาตให้มีการเปลี่ยนแปลงแอมพลิจูด (ปริมาตรเต็มคือ 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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.