如何在软件中解调AFSK信号


14

我正在尝试通过音频通道(扬声器/麦克风)将二进制数据从一台设备传输到另一台设备。我在分组无线电中使用AFSK(音频频移键控),具有和两个频率f m a r k = 1200  Hzf s p a c e = 2200  Hz。我在Ruby中玩了一些,而我的第一个实现只是模仿了一个经典的非相干解调器,到目前为止,它仍然可以正常工作。1200 鲍德F一种[Rķ=1200 赫兹Fsp一种CË=2200 赫兹

问题是,我正在尝试将其移植到移动平台上,在该平台上性能是一个问题,而我目前的解决方案太慢了。我发现了许多方法可以在软件中解调AFSK:

  • 滑动DFT(FFT)
  • 滑动Görtzel过滤器
  • 锁相环
  • 过零

怎么走?可供选择的选项太多。我相信还有更多选择。也许有比我上面提到的解决方案更好的解决方案?有人甚至为我提供了代码示例吗?我担心

  • 性能(应在移动平台(例如iOS或Android设备)上运行)
  • 稳定(应该能够处理一些噪音)

任何建议和提示,不胜感激!


3
我认为您可能会卖空您定位的移动设备的功能。请记住,现代设备是时钟速度超过1 GHz的多核处理器。使用FSK解调器处理<10 ksps信号应该不会出现性能问题。但是,您的现有方法(在我看来像标记/空间过滤)不应不能在现代移动平台上实时运行的任何理由都没有。甚至更复杂的基于PLL的方法也应该适合您的处理范围。我会介绍一下您现有的代码。
杰森·R

Answers:


9

我认为,在具有锁相环的解调器误码率(BER)方面,您可以获得最佳性能。但是,您需要它快速。我认为,对于性能仍然不错的快速算法,最好的选择是过零。

附带一提,我建议您将2200 Hz更改为2400 Hz。朴素的1200/2200 Hz方案实施会产生不连续性,如下图所示大约三分之二,其中2200 Hz转换为1200 Hz。

1200 Hz和2200 Hz

为了最小化您正在使用的带宽并避免不连续性会使信号失真,您需要使相位连续。即使使发射机相位连续,也仍然存在一个问题,即由于相位不同,2200 Hz符号不会总是具有相同数量的零交叉。通常他们会有四个零交叉,但有时他们会有三个。另一方面,由于波特率均匀地划分为FSK频率,因此1200 Hz符号将始终具有两个零交叉。

您可以通过将2200 Hz更改为2400 Hz来解决这两个问题。然后,符号将始终以0度开始和结束(因此自动使它们相位连续),并且它们将始终具有相同数量的零交叉点-两个和四个。

1200 Hz和2400 Hz


嘿吉姆,谢谢您的详细回答!我的调制器实际上执行CPFSK,因此不连续性不是问题。我故意选择1200和2200 Hz,因为谐波的重叠不如1200的倍数大。或者我在这里错了吗?PLL听起来很棒,但是我真的不知道如何实现它们。您是否知道关于软件PLL的任何有用资料?
Patrick Oscity 2012年

@Patrick不,您正确的是1200和2400 Hz会有重叠的谐波。但是,在零交叉的情况下,我认为谐波并不重要。而且,恐怕我不知道有关PLL的良好在线资源。
Jim Clay 2012年

这是不正确的。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

我使用1200 Hz和2200 Hz的相关接收机为AFSK(贝尔202标准)制作了一个解码器,效果非常好。

cos,然后将它们分别积分,并计算出绝对(平方)值。

产生的幅度与信号相位完全无关,并且输出SNR很好。


这正是我以前尝试过的,也就是我所说的“经典非相干解调器”。也许我的实现是错误的,但是我担心由于处理缓慢而导致缓冲区溢出。不管怎么说,还是要谢谢你!
Patrick Oscity 2012年

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

要使用它,请生成下一个正弦波样本并调用此函数,然后检查返回值是否不等于2。如果它不等于2,则前进到下一个符号并确定是否要发送空格标记,然后在发现返回值不等于2时执行的代码块中再次调用此函数。

这是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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.