二元对称信道模拟器
实验目的
加深理解二进制对称信道的工作原理,掌握通过高级编程语言生成伪随机数的方法。允许使用编程语言:C,C++等
实验要求
输入:BSC信道的错误概率,任意的二进制序列
输出:经BSC信道传输后的二进制序列
实验内容
二元对称信道定义
2元对称信道信道的转移概率为
P(j|k)={1−p, k=jp, k≠j, k,j=0,1,...
p表示错误概率。
如下图所示
对于二元对称信道DMC,其信道容量为
C=1−H(p)
C、C++产生伪随机数原理
C++中常用rand()函数生成随机数,但严格意义上来讲生成的只是伪随机数(pseudo-random integral number)。生成随机数时需要我们指定一个种子,如果在程序内循环,那么下一次生成随机数时调用上一次的结果作为种子。但如果分两次执行程序,那么由于种子相同,生成的“随机数”也是相同的。在工程应用时,我们一般将系统当前时间(Unix时间)作为种子,这样生成的随机数更接近于实际意义上的随机数。
rand函数不是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。如果你在第一次调用rand()之前没有调用srand(),那么系统会为你自动调用srand()。而使用同种子相同的数调用 rand()会导致相同的随机数序列被生成。
srand((unsigned)time(NULL))则使用系统定时/计数器的值作为随机种子。每个种子对应一组根据算法预先生成的随机数,所以,在相同的平台环境下,不同时间产生的随机数会是不同的,相应的,若将srand(unsigned)time(NULL)改为srand(TP)(TP为任一常量),则无论何时运行、运行多少次得到的“随机数”都会是一组固定的序列,因此srand生成的随机数是伪随机数。
标准库中的两个用于产生随机数的函数srand()和rand().
函数原型:int rand(void)
返回值:返回一个[0, RAND_MAX]间的随机整数
函数原型:void srand(unsigned seed)
输入参数:seed是rand()的种子,用来初始化rand()的起始值。
系统在调用rand()之前都会自动调用srand(),如果用户在rand()之前曾调用过srand()给参数seed指定了一个值,那么 rand()就会将seed的值作为产生伪随机数的初始值;而如果用户在rand()前没有调用过srand(),那么系统默认将1作为伪随机数的初始 值。如果给了一个定值,那么每次rand()产生的随机数序列都是一样的
所以为了避免上述情况的发生我们通常用srand((unsigned)time(0))或者srand((unsigned)time(NULL))来 产生种子。如果仍然觉得时间间隔太小,可以在(unsigned)time(0)或者(unsigned)time(NULL)后面乘上某个合适的整数。
二元对称信道的仿真实现
程序主函数
int main()
{
print();
float P_error;
Info *root = new Info;
cout << "!------请输入二元信道的错误概率:-----!" << endl <<"P_error =";
cin >> P_error;
getchar();
getBinaryString(root, P_error);
putBinaryString(root);
getchar();
}
程序流程很简单,首先输入二元对称信道的错误概率,然后输入二元序列,最后将通过通道的二元对称序列输出。在输入二元序列的过程我采用链表的形式存储每一个二元码。对应的结构为:
struct Info
{
unsigned char source;
unsigned char output;
struct Info *next;
};
通过链表进行存储,有这样一个好处就是你不需要提前分配空间,程序会判断输入流中是否含有0或1的码,然后对给每一个码动态的分配存储空间,这样既不会造成提前分配很多空间造成空间浪费,也不会因为码字过长造成缓冲区溢出。
输入函数的代码如下
void getBinaryString(Info *root, float P)
{
unsigned char num;
Info *node = root;
Info *before;
cout << "!-----请输入二元信号序列:------!" << endl << endl;
num = cin.get();
srand((unsigned)time(NULL));
do
{
node->source = num;
float x;
x = rand();
x = x / float(RAND_MAX);
if (x < P)
{
if (num == '0')
{
node->output = '1';
}
if (num == '1')
{
node->output = '0';
}
}
else
{
node->output = num;
}
num = cin.get();
node->next = new Info;
before = node;
node = node->next;
} while (num == '0' || num == '1');
before->next = NULL;
}
输入函数的参数包括错误概率和根节点的地址,程序运行结束将会在根节点后链接读入的二元码信息,并完成通过信道的操作。
输出函数的代码如下
void putBinaryString(Info *root)
{
Info *node = root;
cout << endl << "!-------输出的二元序列为:-------!" << endl << endl;
while (node != NULL)
{
cout.put(node->output);
node = node->next;
}
cout << endl << "!-------仿真程序运行结束-------!" << endl << endl;
}
输出函数执行的功能就是将链表中的通过信道后的数据输出。
程序仿真结果如下图所示
可以看出此次仿真输入的错误概率为0.3,输出序列和输入序列有两个位是不同的,也就是通过信道时受到了干扰。下面我们看两种极端的情况,就能更高的理解二元对称信道的仿真过程了。
上图是错误概率为0时的仿真结果,可以看出输入的二元字符串和输出的字符串是完全一样的,即通过信道的过程不会发生错误。
上图是错误概率为1时的结果,可以看出,输入的二元字符串和输入的二元字符正好对应位置相反,及每一位的码字经过信道时都发生了错误。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)