吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 18870|回复: 91
收起左侧

[其他原创] 使用电脑声卡来实现2FSK数据调制解调传输

  [复制链接]
lizhirui 发表于 2019-4-9 08:43
本帖最后由 lizhirui 于 2019-4-19 11:36 编辑

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, 下载次数: 189)

免费评分

参与人数 31吾爱币 +35 热心值 +29 收起 理由
15639063963 + 1 + 1 分析到位
oxxo119 + 1 + 1 谢谢@Thanks!感觉牛逼了
爱飞的猫 + 3 + 1 用心讨论,共获提升!
xxxlsy + 1 + 1 热心回复!
小Q主人 + 1 + 1 谢谢@Thanks!
kerwining + 1 + 1 用心讨论,共获提升!
tanghengvip + 1 + 1 惊!电脑之间偷偷用高频率进行沟通!
chixinfeng + 1 + 1 热心回复!
wohose + 1 + 1 我很赞同!
guoruihotel + 1 + 1 谢谢@Thanks!
名字以后会后悔 + 1 + 1 谢谢@Thanks!
安倚静轩 + 1 + 1 用心讨论,共获提升!
wangbingbing + 1 + 1 仰视大佬,抱大腿
yangsd973 + 1 + 1 热心回复!
daniel7785 + 1 + 1 用心讨论,共获提升!
如影随风 + 1 + 1 我很赞同!
hwolf1 + 1 + 1 方式很新颖!
ayoma + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
snowhalation + 1 用心讨论,共获提升!
HDxian + 1 + 1 用心讨论,共获提升!
qiangcl + 1 热心回复!
qq3bot + 1 + 1 谢谢@Thanks!
fanssong + 1 + 1 表示一脸懵逼
moodykeke + 1 + 1 谢谢@Thanks!
qsvren + 1 + 1 青果摄像头就是使用的音频传输的数据来连接加密wifi
wingingangel + 1 + 1 用心讨论,共获提升!
whc2001 + 2 + 1 卧槽牛逼, 之前那种音频口的刷卡器似乎就是用这种协议通讯的, 一直没研究透
cunzher + 1 + 1 牛逼
苏紫方璇 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
GenW + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zzzain46 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| lizhirui 发表于 2019-4-13 13:30
ayoma 发表于 2019-4-13 01:38
这个其实我们HAM玩的无线电 JT65 PSK JT9... 和现在流行的FT8软件wsjtx和jtdx是一样的原理。希望能有中文传 ...

支持啊 我也是HAM 23333
 楼主| lizhirui 发表于 2019-4-9 12:15
zwo 发表于 2019-4-9 09:40
如果为了提高传速率,改到4FSK, 8FSK,是不是误码率会很大?

如果频率间隔比较大的话,并且你的滤波器够窄的话 问题也不大
其实这玩意如果不用PC改用嵌入式处理器运行裸机程序的话,传输速度上到几KB/s是一点压力没有
如果提高两个传输频率的话,传输上到几MB/s 几十MB/s的也没啥大问题
chensure 发表于 2019-4-9 09:16
之前听说过,黑一台无网络的计算器,就用这种方式?
goldli 发表于 2019-4-9 09:21
一运行就报错。win10

点评

已经编译好的EXE需要在至少.net Framework 4.7.1的环境下启动(版本过低可能会报异常),并且可能需要在插入麦克风和扬声器之后才能成功启动,否则对于某些声卡可能会报异常  详情 回复 发表于 2019-4-9 09:23
 楼主| lizhirui 发表于 2019-4-9 09:23
goldli 发表于 2019-4-9 09:21
一运行就报错。win10

已经编译好的EXE需要在至少.net Framework 4.7.1的环境下启动(版本过低可能会报异常),并且可能需要在插入麦克风和扬声器之后才能成功启动,否则对于某些声卡可能会报异常
zwo 发表于 2019-4-9 09:40
如果为了提高传速率,改到4FSK, 8FSK,是不是误码率会很大?

点评

目前2FSK在PC上现有速率下的测试显示 目前传输还没出过错,所以不知道误码率是多少  详情 回复 发表于 2019-4-9 12:15
如果频率间隔比较大的话,并且你的滤波器够窄的话 问题也不大 其实这玩意如果不用PC改用嵌入式处理器运行裸机程序的话,传输速度上到几KB/s是一点压力没有 如果提高两个传输频率的话,传输上到几MB/s 几十MB/s的也  详情 回复 发表于 2019-4-9 12:15
chengan1998 发表于 2019-4-9 09:58
大佬我来了
苏紫方璇 发表于 2019-4-9 10:59
大佬好厉害,长知识了
 楼主| lizhirui 发表于 2019-4-9 12:15
zwo 发表于 2019-4-9 09:40
如果为了提高传速率,改到4FSK, 8FSK,是不是误码率会很大?

目前2FSK在PC上现有速率下的测试显示
目前传输还没出过错,所以不知道误码率是多少
goldli 发表于 2019-4-9 14:18
lizhirui 发表于 2019-4-9 09:23
已经编译好的EXE需要在至少.net Framework 4.7.1的环境下启动(版本过低可能会报异常),并且可能需要在 ...

我这有4.7.2了。 没有麦克风
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 15:52

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表