Yazılımda AFSK sinyali nasıl demodüle edilir


14

Bir ses kanalı (hoparlör / mikrofon) üzerinden bir cihazdan diğerine ikili veri aktarmaya çalışıyorum. AFSK (Ses Frekansı Kaydırma Anahtarlaması) Paket Radyoda olduğu gibi ve iki frekans f m a r k = 1200  Hz ve f s p a c e = 2200  Hz ile kullanıyorum . Ruby'de biraz oynadım ve ilk uygulamam şimdiye kadar iyi çalışan klasik tutarsız bir demodülatörü taklit ediyor.1200 Baudfmark=1200 Hzfspace=2200 Hz

Sorun, ben performans bir endişe ve benim mevcut çözüm çok yavaş bir mobil platforma bu çalışıyorum. Yazılımda AFSK'yi demodüle etmenin çeşitli yollarını buldum:

  • Kayar DFT (FFT)
  • Sürgülü Görtzel Filtresi
  • Faz Kilitli Döngü
  • Sıfır Geçiş

Gidilecek yol ne olurdu? Aralarından seçim yapabileceğiniz çok fazla seçenek var. Eminim daha da fazla seçenek var. Belki de yukarıda söylediğimden daha iyi çözümler var mı? Birisinin benim için kod örnekleri bile var mı? İle ilgileniyorum

  • Performans (mobil Platformda çalıştırılmalıdır, örneğin bir iOS veya Android cihaz)
  • Kararlılık (biraz gürültü ile başa çıkabilmelidir)

Herhangi bir öneri ve ipuçları büyük beğeni topluyor!


3
Sanırım, hedeflediğiniz mobil cihazların yeteneklerini kısa sürede satacağınızı düşünüyorum. Modern cihazların saat hızları 1 GHz'i aşan çok çekirdekli işlemciler olduğunu unutmayın. FSK demodülatörüyle <10 ksps'lik bir sinyalin işlenmesi bir performans sorunu göstermemelidir. Ancak mevcut yaklaşımınızın (bana işaret / alan filtreleme gibi geliyor) modern bir mobil platformda gerçek zamanlı olarak çalışmaması için herhangi bir neden olmamalıdır. Daha sofistike bir PLL tabanlı yaklaşım bile işleme zarfınıza rahatça sığmalıdır. Mevcut kodunuzu biraz profillendirirdim.
Jason R

Yanıtlar:


9

Bir faz kilitli döngü ile demodülatör bit hata oranı (BER) açısından en iyi performansı elde edebileceğinizi düşünüyorum. Yine de hızlı olması gerekir. Ben hala makul iyi performans hızlı bir algoritma için en iyi bahis sıfır geçiş olduğunu düşünüyorum.

Bir yan notta, 2200 Hz'yi 2400 Hz olarak değiştirmenizi öneririm. 1200/2200 Hz şemasının saf bir şekilde uygulanması, aşağıdaki grafikte yaklaşık üçte ikisinden de görüldüğü gibi, süreksizliklere neden olacak ve 2200 Hz, 1200 Hz'e geçecektir.

1200 Hz ve 2200 Hz

Kullandığınız bant genişliğini en aza indirmek ve sinyali bozacak kesintilerden kaçınmak için fazı sürekli hale getirmeniz gerekir. Verici fazını sürekli kılsanız bile, 2200 Hz sembollerin farklı fazlardan dolayı her zaman aynı sayıda sıfır geçişe sahip olmaması sorunu devam edecektir. Genellikle dört sıfır geçişleri olur, ancak bazen üç geçişleri olur. Öte yandan 1200 Hz sembolleri her zaman iki sıfır geçişe sahip olacaktır, çünkü baud hızı FSK frekansına eşit olarak bölünür.

2200 Hz değerini 2400 Hz olarak değiştirerek bu sorunların her ikisini de çözebilirsiniz. Daha sonra semboller her zaman 0 derecede başlar ve biter (böylece otomatik olarak fazı sürekli hale getirir) ve her zaman aynı sayıda sıfır geçişe sahip olurlar - iki ve dört.

1200 Hz ve 2400 Hz


Hey Jim, detaylı cevabınız için teşekkürler! Modülatörüm aslında CPFSK yapıyor, bu nedenle süreksizlikler sorun değil. Kasıtlı olarak 1200 ve 2200 Hz seçtim, çünkü harmonikler 1200 katları kadar örtüşmüyor. Yoksa burada yanlış mıyım? PLL'ler kulağa hoş geliyor, ama onları nasıl uygulayacağımı gerçekten bilmiyorum. Yazılım PLL'leri hakkında iyi kaynakları biliyor musunuz?
Patrick Oscity

@Patrick Hayır, 1200 ve 2400 Hz'nin çakışan harmoniklere sahip olacağından eminsiniz. Sıfır geçiş bağlamında, harmoniklerin önemli olduğunu düşünmüyorum. Ve hayır, korkarım ki PLL'ler hakkında iyi bir çevrimiçi kaynak bilmiyorum.
Jim Clay

Bu doğru değil. AFSK 1200 Bell 202'yi takip eder ve tonların 1200 ve 2200 olması gerektiğini söyler. Süreksizlik asla verici tarafında olmamalıdır. Açık kaynak AFSK 1200 modülatörlerine göz atın, modülasyon her ton için bir faz artışı izleyerek yapılır: eğer ton == DÜŞÜK sonra last_phase + = ph_low else last_phase + = ph_high endif; next_sample = sin (son_faz);
vz0

5

1200 Hz ve 2200 Hz için korelasyon alıcıları kullanarak AFSK (Bell 202 standardı) için bir kod çözücü yaptım ve çok iyi sonuçlar elde ettim.

sincos

Ortaya çıkan genlik sinyal fazından oldukça bağımsızdır ve çıkış SNR'si çok iyidir.


Bu tam olarak daha önce denedim ve "klasik tutarsız demodülatör" dediğim şeydir. Belki benim uygulamam hatalı, ama yavaş işleme nedeniyle arabellek taşması muzdarip korkuyorum. Yine de teşekkürler!
Patrick Oscity

0

RTTY 45.45 baud durumunda, tamsayı sayıda örnek olmayan sembollere de sahip olursunuz, bu nedenle her örnek olarak çağrılabilecek bir işleve ihtiyacınız olur ve daha sonra bu sembol sona erdiğinde dönüş değerinde sinyal verir. Ve sinüs dalgasının fazının bulunduğu yerde çalışan bir taksitli tutan bir faz akümülatörüne ihtiyacınız var.

Uzunluğu örnek hızının tam katı olmayan semboller göndermek için bu işleve ihtiyacınız vardır ...

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

Bunu kullanmak için bir sonraki sinüs dalgası örneği oluşturun ve bu işlevi çağırın, ardından dönüş değerinin ikiye eşit OLMADIĞINI kontrol edin. İkiye eşit değilse, bir sonraki sembole ilerleyin ve bir boşluk işareti gönderip göndermediğinize karar verin, ardından dönüş işlevinin ikiye eşit olmadığını öğrendiğinizde yürütülen kod bloğunda bu işlevi tekrar çağırın.

Ve burada Rockbox ürün yazılımından faz akümülatörü, genlikteki değişikliklere izin vermek için bir değişiklikle (tam hacim 32767, faz dışı 180 derece tam hacim -32768'dir).

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.