最新公告
  • 欢迎您光临小酒资源吧,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • 使用电脑声卡来实现2FSK数据调制解调传输

    使用电脑声卡来实现2FSK数据调制解调传输 最后编辑:2020-09-01
    增值服务: 自动发货 使用说明 安装指导 环境配置二次开发BUG修复

    QQ截图20190409081953.png

    此程序在物理层上使用10KHz的频率表示逻辑“0”,使用15KHz的频率表示逻辑“1”
    在物理层之上(假设就叫传输层吧)用一个单位时间的0和一个单位时间的1表示逻辑“0”,用一个单位时间的0和两个单位时间的1表示逻辑“1”,并且每个字节的结尾都有一个偶校验位以及一个保持较长时间的0用于分隔字节
    在传输层之上(假设就叫网络层吧),以包为单位传输数据,0x55表示包头,0xAA表示包尾,无校验

    程序解调原理是:
    首先利用10KHz和15KHz带通滤波器将声卡接收来的波形进行滤波,然后将两通道分别通过两个包络检波器,之后在门限噪声过滤后进行比较,谁幅度大判决结果就是谁
    滤波器使用MATLAB生成的,值如下所示:
    [C#] 纯文本查看 复制代码
    private const int BandPass_Size = 45;

    private static double[] BandPass_10KHz = new double[]{
    0.0009781904976227,2.310687083045e-05,-0.001850921386016,-0.0009604556387189,
    0.002732177361363, 0.002454026683306,-0.003530807893481,-0.005033359378625,
    0.003268338256639, 0.008046002294271,-0.001785884965235, -0.01118839681511,
    -0.001425109899399, 0.01337602169719, 0.005932600339844, -0.01398968593694,
    -0.01124059666706, 0.01232758211354, 0.016159778255,-0.008524876132051,
    -0.01973020933926, 0.003023046445069, 0.02098489087997, 0.003023046445069,
    -0.01973020933926,-0.008524876132051, 0.016159778255, 0.01232758211354,
    -0.01124059666706, -0.01398968593694, 0.005932600339844, 0.01337602169719,
    -0.001425109899399, -0.01118839681511,-0.001785884965235, 0.008046002294271,
    0.003268338256639,-0.005033359378625,-0.003530807893481, 0.002454026683306,
    0.002732177361363,-0.0009604556387189,-0.001850921386016,2.310687083045e-05,
    0.0009781904976227
    };

    private static double[] BandPass_15KHz = new double[]{
    -0.0009981746791559, 0.000759180810415,0.0006404064214932,-0.002457709613472,
    0.00238467384023,0.0007556946095888,-0.004687333695163, 0.004906581539168,
    0.0005502824808439,-0.007567247883353, 0.00864646206089,-0.0006606208202895,
    -0.01018615121518, 0.01288307335994,-0.002755953433256, -0.01205731207217,
    0.01703290275592,-0.005710913930339, -0.01241906755974, 0.01996890238488,
    -0.008755521713043, -0.01126587989407, 0.02109366603246, -0.01126587989407,
    -0.008755521713043, 0.01996890238488, -0.01241906755974,-0.005710913930339,
    0.01703290275592, -0.01205731207217,-0.002755953433256, 0.01288307335994,
    -0.01018615121518,-0.0006606208202895, 0.00864646206089,-0.007567247883353,
    0.0005502824808439, 0.004906581539168,-0.004687333695163,0.0007556946095888,
    0.00238467384023,-0.002457709613472,0.0006404064214932, 0.000759180810415,
    -0.0009981746791559
    };

    滤波程序如下(原理是将信号与滤波器进行卷积,卷积使用了一个滚动缓冲区来解决):
    [C#] 纯文本查看 复制代码
    private int[] Filter_10KHz(int[] Data)
    {
    double[] dData = new double[Data.Length];
    int i,j,k;

    for(i = 0;i < dData.Length;i++)
    {
    dData[i] = 0;
    k = BandPass_Size – 1;

    for(j = i + 1;j < BandPass_Size;j++)
    {
    dData[i] += BandPassBuf_10KHz[j] * BandPass_10KHz[k–];
    }

    for(j = Math.Max(0,i – BandPass_Size + 1);j <= i;j++)
    {
    dData[i] += ((double)Data[j]) * BandPass_10KHz[k–];
    }

    if(k != -1)
    {
    throw new Exception();
    }
    }

    for(i = Data.Length – 1,j = BandPass_Size – 1;j >= 0;i–,j–)
    {
    BandPassBuf_10KHz[j] = (double)Data[i];
    }

    int[] r = new int[Data.Length];

    for(i = 0;i < Data.Length;i++)
    {
    r[i] = (int)dData[i];
    }

    return r;
    }

    private int[] Filter_15KHz(int[] Data)
    {
    double[] dData = new double[Data.Length];
    int i,j,k;

    for(i = 0;i < dData.Length;i++)
    {
    dData[i] = 0;
    k = BandPass_Size – 1;

    for(j = i + 1;j < BandPass_Size;j++)
    {
    dData[i] += BandPassBuf_15KHz[j] * BandPass_15KHz[k–];
    }

    for(j = Math.Max(0,i – BandPass_Size + 1);j <= i;j++)
    {
    dData[i] += ((double)Data[j]) * BandPass_15KHz[k–];
    }

    if(k != -1)
    {
    throw new Exception();
    }
    }

    for(i = Data.Length – 1,j = BandPass_Size – 1;j >= 0;i–,j–)
    {
    BandPassBuf_15KHz[j] = (double)Data[i];
    }

    int[] r = new int[Data.Length];

    for(i = 0;i < Data.Length;i++)
    {
    r[i] = (int)dData[i];
    }

    return r;
    }

    包络检波器代码如下(同样采用了滚动缓冲区):
    [C#] 纯文本查看 复制代码
    private double env_3(double x,double rct)
    {
    if(rct == 0.0)
    {
    old_y = 0.0;
    }
    else
    {
    x = Math.Abs(x);

    if(x > old_y)
    {
    old_y = x;
    }
    else
    {
    old_y *= rct / (rct + 1);
    }
    }

    return old_y;
    }

    private void env_4(double[] x,out double[] y,int N,double rct)
    {
    double xx = 0.0;
    int i;

    old_y = 0.0;

    y = new double[N];

    y[0] = Math.Abs(x[0]);

    for(i = 1; i < N; i++)
    {
    xx = Math.Abs(x[i]);

    if(xx > y[i – 1])
    {
    y[i] = xx;
    }
    else
    {
    y[i] = y[i – 1] * rct / (rct + 1);
    }
    }
    }

    private int[] Env_10KHz(int[] Data)
    {
    double[] dData = null;
    double[] dr;
    int i,j,k;

    if(Env10KHzInit)
    {
    dData = new double[Data.Length];

    for(i = 0;i < Data.Length;i++)
    {
    dData[i] = Data[i];
    }

    Env10KHzInit = false;
    }
    else
    {
    dData = new double[Data.Length << 1];

    for(i = 0;i < Data.Length;i++)
    {
    dData[i] = Env10KHzBuf[i];
    }

    for(i = 0;i < Data.Length;i++)
    {
    dData[Data.Length + i] = Data[i];
    }
    }

    env_4(dData,out dr,dData.Length,rc);

    int[] r = new int[Data.Length];

    if(Data.Length == dr.Length)
    {
    for(i = 0;i < dr.Length;i++)
    {
    r[i] = (int)dr[i];
    }
    }
    else
    {
    for(i = Data.Length;i < dr.Length;i++)
    {
    r[i – Data.Length] = (int)dr[i];
    }
    }

    Env10KHzBuf = Data.ToArray();

    return r;
    }

    private int[] Env_15KHz(int[] Data)
    {
    double[] dData = null;
    double[] dr;
    int i,j,k;

    if(Env15KHzInit)
    {
    dData = new double[Data.Length];

    for(i = 0;i < Data.Length;i++)
    {
    dData[i] = Data[i];
    }

    Env15KHzInit = false;
    }
    else
    {
    dData = new double[Data.Length << 1];

    for(i = 0;i < Data.Length;i++)
    {
    dData[i] = Env15KHzBuf[i];
    }

    for(i = 0;i < Data.Length;i++)
    {
    dData[Data.Length + i] = Data[i];
    }
    }

    env_4(dData,out dr,dData.Length,rc);

    int[] r = new int[Data.Length];

    if(Data.Length == dr.Length)
    {
    for(i = 0;i < dr.Length;i++)
    {
    r[i] = (int)dr[i];
    }
    }
    else
    {
    for(i = Data.Length;i < dr.Length;i++)
    {
    r[i – Data.Length] = (int)dr[i];
    }
    }

    Env15KHzBuf = Data.ToArray();

    return r;
    }

    传输层数据接收程序:
    [C#] 纯文本查看 复制代码
    private void DataArrived_Audio(int[] audioData)
    {
    var r10 = Filter_10KHz(audioData);
    var re10 = Env_10KHz(r10);
    var r15 = Filter_15KHz(audioData);
    var re15 = Env_15KHz(r15);
    var v = 0;

    for(int i = 0;i < re10.Length;i++)
    {
    statusChart1.Value = v = (((re10[i] < CurTValue) && (re15[i] < CurTValue)) ? 0 : (re10[i] > re15[i] ? 10000 : 30000));
    statusChart2.Value = re10[i];
    statusChart3.Value = re15[i];

    if(v == 30000)
    {
    if(LastOne)
    {
    OneCnt++;
    }
    else
    {
    LastOne = true;
    OneCnt = 1;
    }
    }
    else if(v == 0)
    {
    //无效
    ZeroCnt = 0;
    OneCnt = 0;
    LastOne = false;
    CurBit = 0;
    CurValue = 0;
    }
    else
    {
    if(LastOne)
    {
    //一个bit接收完成

    if((ZeroCnt >= LowValue) && (OneCnt >= LowValue))
    {
    if(OneCnt > CenterValue)
    {
    //判定为1
    CurValue |= (1 << CurBit);
    CurBit++;
    }
    else
    {
    //判定为0
    CurBit++;
    }

    if(CurBit >= 9)
    {
    var check = 0;

    for(int j = 0;j < 8;j++)
    {
    check ^= (CurValue >> j) & 0x01;
    }

    if(check == (CurValue >> 8))
    {
    RevQ.Enqueue((byte)(CurValue & 0xFF));
    }

    ZeroCnt = 0;
    CurBit = 0;
    CurValue = 0;
    }
    }

    LastOne = false;
    ZeroCnt = 1;
    }
    else
    {
    ZeroCnt++;
    }
    }
    }

    }

    传输层数据发送函数:
    [C#] 纯文本查看 复制代码
    private void DataSendThread()
    {
    while(true)
    {
    var check = 0;
    var list = new List<byte>();

    if(SendQ.Count > 0)
    {
    var x = SendQ.Dequeue();

    for(int i = 0;i < 8;i++)
    {
    if((x & (1 << i)) == 0)
    {
    check ^= 0;
    /*m_Fifo.Write(Signal10KHz,0,Signal10KHz.Length / 2);
    m_Fifo.Write(Signal15KHz,0,Signal15KHz.Length / 2);*/
    AddToList(list,Signal10KHz,Signal10KHz.Length / ZeroDiv);
    AddToList(list,Signal15KHz,Signal15KHz.Length / ZeroDiv);
    }
    else
    {
    check ^= 1;
    /*m_Fifo.Write(Signal10KHz,0,Signal10KHz.Length / 2);
    m_Fifo.Write(Signal15KHz,0,Signal15KHz.Length);*/
    AddToList(list,Signal10KHz,Signal10KHz.Length / ZeroDiv);
    AddToList(list,Signal15KHz,Signal15KHz.Length / OneDiv);
    }
    }

    if(check == 0)
    {
    AddToList(list,Signal10KHz,Signal10KHz.Length / ZeroDiv);
    AddToList(list,Signal15KHz,Signal15KHz.Length / ZeroDiv);
    }
    else
    {
    AddToList(list,Signal10KHz,Signal10KHz.Length / ZeroDiv);
    AddToList(list,Signal15KHz,Signal15KHz.Length / OneDiv);
    }

    AddToList(list,Signal10KHz,Signal10KHz.Length / 2);
    }

    m_Fifo.Write(list.ToArray(),0,list.Count);
    }
    }

    该代码抗干扰能力很强,大声说话甚至喊叫都不会影响到声音传输,如果你那里一直接收不到数据,可能是你的扬声器发不出10KHz和15KHz的声音或者声音太小,这时可以采用音频线直接连接声卡的输入端和输出端
    该程序在Windows 7 x64旗舰版下测试通过,由于受限于Windows的多任务调度机制,程序的实时性很难得到保证,因此传输速度只能达到4bit/s即0.5Byte/s或者说2s/Byte
    发送速率可以由“speed”变量控制,该变量位于Form1类成员中

    已经编译好的EXE需要在至少.net Framework 4.7.1的环境下启动(版本过低可能会报异常),并且可能需要在插入麦克风和扬声器之后才能成功启动,否则对于某些声卡可能会报异常
    代码基于VS2017开发
    窗口左下角的发送值只能填0-255之间的一个数,否则会报异常,那里是单字节的发送测试
    右上角那个文本框可以输入任意文本,点击发送之后等待接收即可,那里是以包为单位发送的,因此若发送x个字符,实际发送的是(f(x)+2)*9个bit(包头一个字节,包尾一个字节,UTF-8编码表示编码的长度不定,所以x字符实际对应的字符数用f(x)表示,对于汉字而言,是三个字节表示一个字符),
    下载链接:

    音频数据传输GUI.rar

    (476.74 KB, 下载次数: 150)

    2019-4-9 08:41 上传

    猜你在找

    1. 本站所有资源来源于用户上传和网络,因此不包含技术服务请大家谅解!如有侵权请邮件联系客服!603313839@qq.com
    2. 本站不保证所提供下载的资源的准确性、安全性和完整性,资源仅供下载学习之用!如有链接无法下载、失效或广告,请联系客服处理,有奖励!
    3. 您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容资源!如用于商业或者非法用途,与本站无关,一切后果请用户自负!
    4. 如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!

    小酒资源吧 » 使用电脑声卡来实现2FSK数据调制解调传输

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    免责声明/技术服务/售后服务等
    本站所有资源来源于用户上传和网络,因此不包含技术服务请大家谅解!如有侵权请邮件联系客服!603313839@qq.com
    • 2020-09-01Hi,初次和大家见面了,请多关照!

    售后服务:

    • 售后服务范围 1、商业模板使用范围内问题免费咨询
      2、源码安装、模板安装(一般 ¥50-300)服务答疑仅限SVIP用户
      3、单价超过500元的程序/模板免费一次安装,需提你供服务器信息。
      付费增值服务 1、提供dedecms模板、WordPress主题、discuz模板优化等服务请详询在线客服
      2、承接 WordPress、DedeCMS、Discuz 等系统建站、仿站、开发、火车头规则、定制等服务
      3、服务器环境配置(一般 ¥50-300)
      4、网站中毒处理(需额外付费,500元/次/质保三个月)
      售后服务时间 周一至周日(法定节假日除外) 9:00-22:00
      免责声明 本站所提供的模板(主题/插件)等资源仅供学习交流,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担,有部分资源为网上收集或仿制而来,若模板侵犯了您的合法权益,请来信通知我们(Email: 603313839@qq.com),我们会及时删除,给您带来的不便,我们深表歉意!

    Hi, 如果你对这款程序/模板/下载/有疑问,可以跟我联系哦!

    联系作者
    • 2904会员总数(位)
    • 4494资源总数(个)
    • 1本周发布(个)
    • 0 今日发布(个)
    • 386稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情
  • 2020 XiaoJiu8.cn - & WordPress Theme. All rights reserved 黔ICP备17003460号-5

  • XML地图 | 站长导航
         
    升级SVIP尊享更多特权立即升级