Cara mendemodulasi sinyal AFSK dalam perangkat lunak

14

Saya mencoba mengirimkan data biner dari satu perangkat ke perangkat lain melalui saluran audio (speaker / mic). Saya menggunakan AFSK (Audio Frequency Shift Keying) seperti dalam Packet Radio, dengan dan dua frekuensi f m a r k = 1200  Hz dan f s p a c e = 2200  Hz . Saya bermain-main sedikit di Ruby dan implementasi pertama saya hanya meniru demodulator tidak koheren klasik, yang berfungsi dengan baik, sejauh ini.1200 BaudfmSebuahrk=1200 HzfshalSebuahce=2200 Hz

Masalahnya adalah, saya mencoba port ini ke platform mobile di mana kinerja menjadi perhatian dan solusi saya saat ini terlalu lambat. Saya telah menemukan banyak cara untuk mendemodulasi AFSK dalam perangkat lunak:

  • Sliding DFT (FFT)
  • Sliding Görtzel Filter
  • Fase Terkunci Loop
  • Zero Crossing

Apa yang akan menjadi cara untuk pergi? Ada terlalu banyak opsi untuk dipilih. Saya yakin ada lebih banyak opsi yang tersedia. Mungkin ada solusi yang lebih baik daripada yang saya sebutkan di atas? Apakah ada yang punya contoh kode untuk saya? Saya khawatir

  • Kinerja (harus dijalankan pada Platform seluler, katakanlah perangkat iOS atau Android)
  • Stabilitas (harus mampu menangani beberapa kebisingan)

Setiap saran dan petunjuk sangat dihargai!

Patrick Oscity
sumber
3
Saya pikir Anda cenderung menjual kemampuan perangkat seluler yang Anda targetkan. Ingat bahwa perangkat modern adalah prosesor multicore dengan kecepatan clock lebih dari 1 GHz. Memproses sinyal <10 ksps dengan demodulator FSK seharusnya tidak menimbulkan masalah kinerja. Tetapi seharusnya tidak ada alasan mengapa pendekatan Anda saat ini (yang menurut saya seperti mark / space filtering) seharusnya tidak dapat berjalan secara real time pada platform seluler modern. Bahkan pendekatan berbasis PLL yang lebih canggih harus cocok dengan nyaman dalam amplop pemrosesan Anda. Saya akan sedikit profil kode Anda yang ada.
Jason R

Jawaban:

9

Saya pikir Anda bisa mendapatkan kinerja terbaik dalam hal demodulator bit-error rate (BER) dengan loop fase-terkunci. Anda harus cepat. Saya pikir taruhan terbaik Anda untuk algoritma cepat yang masih berkinerja cukup baik adalah zero crossing.

Sebagai catatan, saya ingin menyarankan Anda mengubah 2200 Hz menjadi 2400 Hz. Implementasi naif skema 1200/2200 Hz akan menghasilkan diskontinuitas, seperti terlihat sekitar dua pertiga ke dalam plot di bawah ini, di mana 2200 Hz transisi ke 1200 Hz.

1200 Hz dan 2200 Hz

Untuk meminimalkan bandwidth yang Anda gunakan dan menghindari diskontinuitas yang akan mendistorsi sinyal Anda harus membuat fase berlanjut. Bahkan jika Anda membuat fase pemancar terus menerus, masih ada masalah bahwa simbol 2200 Hz tidak akan selalu memiliki jumlah penyeberangan nol yang sama karena fase yang berbeda. Biasanya mereka akan memiliki empat penyeberangan nol, tetapi kadang-kadang mereka akan memiliki tiga penyeberangan. Simbol 1200 Hz di sisi lain, akan selalu memiliki dua penyeberangan nol karena baud rate membagi secara merata ke dalam frekuensi FSK.

Anda dapat menyelesaikan kedua masalah ini dengan mengubah 2200 Hz menjadi 2400 Hz. Kemudian simbol akan selalu mulai dan berakhir pada 0 derajat (sehingga secara otomatis membuat mereka fase kontinu), dan mereka akan selalu memiliki jumlah yang sama dari nol penyilangan - dua dan empat.

1200 Hz dan 2400 Hz

Jim Clay
sumber
Hai Jim, terima kasih atas jawaban terinci Anda! Modulator saya benar-benar melakukan CPFSK, oleh karena itu diskontinuitas tidak menjadi masalah. Saya sengaja memilih 1.200 dan 2200 Hz karena harmonik tidak tumpang tindih sebanyak dengan kelipatan 1.200. Atau saya salah di sini? PLL terdengar hebat, tetapi saya benar-benar tidak tahu bagaimana menerapkannya. Apakah Anda mengetahui ada sumber yang bagus tentang PLL perangkat lunak?
Patrick Oscity
@ Patrick Tidak, Anda benar bahwa 1200 dan 2400 Hz akan memiliki harmonik yang tumpang tindih. Dalam konteks zero-crossing, saya tidak berpikir soal harmonisa. Dan tidak, saya khawatir saya tidak tahu sumber online yang bagus tentang PLL.
Jim Clay
Ini tidak benar. AFSK 1200 mengikuti Bell 202, dan dikatakan nada harus 1200 dan 2200. Diskontinuitas seharusnya tidak pernah terjadi di sisi pemancar. Lihat AFSK 1200 modulator open source, modulasi dilakukan dengan melacak kenaikan fase untuk setiap nada: jika nada == RENDAH lalu last_phase + = ph_low lain last_phase + = ph_high endif; next_sample = sin (last_phase);
vz0
5

Saya membuat dekoder untuk AFSK (standar Bell 202) menggunakan penerima korelasi untuk 1200 Hz dan 2200 Hz, dengan hasil yang sangat baik.

dosacos

Amplitudo yang dihasilkan cukup independen dari fase sinyal, dan output SNR sangat baik.

Juancho
sumber
Ini adalah persis apa yang saya coba sebelumnya dan apa yang saya sebut "demodulator inkoheren klasik". Mungkin implementasi saya keliru, tetapi saya khawatir akan mengalami buffer overflows karena pemrosesan yang lambat. Bagaimanapun, terima kasih!
Patrick Oscity
0

Dalam kasus RTTY 45,45 baud, Anda juga akan memiliki simbol yang bukan jumlah integer sampel, jadi Anda memerlukan fungsi yang dapat disebut masing-masing sampel dan memberi sinyal pada nilai pengembaliannya ketika simbol itu telah berakhir. Dan Anda membutuhkan akumulator fase, yang membuat penghitungan berjalan di mana fase gelombang sinus.

Untuk mengirim simbol yang panjangnya bukan kelipatan integer dari laju sampel, Anda memerlukan fungsi ini ...

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

Untuk menggunakannya, hasilkan sampel gelombang sinus berikutnya dan panggil fungsi ini, lalu periksa apakah nilai kembali TIDAK sama dengan dua. Jika tidak sama dengan dua, lanjutkan ke simbol berikutnya dan putuskan apakah Anda mengirim tanda spasi, lalu panggil fungsi ini lagi di dalam blok kode yang dieksekusi ketika Anda mengetahui bahwa nilai balik tidak sama dengan dua.

Dan inilah akumulator fase dari firmware Rockbox, dengan perubahan untuk memungkinkan perubahan amplitudo (volume penuh adalah 32767, 180 derajat dari fase volume penuh adalah -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;
}
Brent Fisher
sumber