1.实验介绍
RFID中,读写区域标签间数据通信为保证通信的准确性,常采用奇偶校验、CRC冗余校验、海明码校验。本实验在学生掌握上述编码原理的基础上,设计软件模拟通信过程,实现数据监督码的计算,统计数据传输的结果。
2.实验目的
- 掌握RFID通信中常采用的数据差错及纠错方法
- 通过编程实现数据监督码的计算及对接收的数据进行检验
3.实验环境
操作系统:Windows 10
软件环境:Visual Studio 2019
4.实验流程
- 设计系统工作流程
- 编程实现
- 观察实验结果,给出实验结论
5.实验内容
软件要求实现下面功能:
- 软件随机生成100个数据,每个数据含有8个二进制位,并且显示。
- 计算100个数据对应的监督码(分别实现奇偶校验、CRC冗余校验、海明校验),并显示
- 模拟数据传输中的干扰(对100个数据的若干二进制位随机干扰),显示干扰后的结果
- 模拟接收方对接收的数据进行校验,显示计算得到的监督码
- 判断哪些数据接收有误,哪些数据虽然验证无误但实际有误,统计传输正确率,并以适当的方式加以显示。
参考页面
1.奇偶校验
红色:检测出错误的数据
绿色:校验位正确但数据错误
2.海明校验
6.实验步骤
6.1主页面
6.2奇偶校验
6.2.1产生随机数函数代码
//获取数字
public int GetNum(int[] arrNum, int tmp, int minValue, int maxValue, Random ra)
{
int n = 0;
while (n <= arrNum.Length - 1)
{
if (arrNum[n] == tmp) //利用循环判断是否有重复
{
tmp = ra.Next(minValue, maxValue); //重新随机获取。
GetNum(arrNum, tmp, minValue, maxValue, ra);//递归:如果取出来的数字和已取得的数字有重复就重新随机获取。
}
n++;
}
return tmp;
}
//产生随机数字
public int[] GetRandomNum(int num, int minValue, int maxValue)
{
Random ra = new Random(unchecked((int)DateTime.Now.Ticks));
int[] arrNum = new int[num];
int tmp = 0;
for (int i = 0; i <= num - 1; i++)
{
tmp = ra.Next(minValue, maxValue); //随机取数
arrNum[i] = GetNum(arrNum, tmp, minValue, maxValue, ra); //取出值赋到数组中
}
return arrNum;
}
6.2.2奇偶校验计算校验位函数代码
//计算校验码
public string GetNum_jy(int x, string s)
{
int jy;
int sum_1 = 0;
char[] a = s.ToCharArray();
for(int i = 0; i < 8; i++)
{
if(a[i] == '1')
{
sum_1++;
}
}
if((x == 1 && sum_1 % 2 == 0) || (x == 0 && sum_1 % 2 != 0))
{
jy = 1;
}
else
{
jy = 0;
}
return jy.ToString();
}
6.2.3模拟干扰函数代码
//模拟干扰
private void Ganrao(string[] bin_r_string)
{
int num_c_sum = new Random().Next(0, 10); //出错总数
Random ran = new Random(unchecked((int)DateTime.Now.Ticks));
for (int i = 0; i < num_c_sum; i++)
{
int num_c = ran.Next(0, 100); //出错的数
int num_c_count = ran.Next(1, 3); //出错位数
int c1 = ran.Next(8); //出错的第一位
int c2 = ran.Next(8); //出错的第二位
char[] a = bin_r_string[num_c].ToCharArray();
//第一位出错
if (a[c1] == '0')
{
a[c1] = '1';
}
else
{
a[c1] = '0';
}
if(num_c_count > 1)
{
//第二位出错
if (a[c2] == '0')
{
a[c2] = '1';
}
else
{
a[c2] = '0';
}
}
bin_r_string[num_c] = new string(a);
}
}
6.2.4校验代码
private void button4_Click(object sender, EventArgs e)
{
this.listView2.BeginUpdate();
this.listView2.Items.Clear();
int jo; //表示奇校验或偶校验
int sum_right = 0; //记录正确的数据个数
int jy_c = 0; //记录校验位错误个数
int bin_c = 0; //记录数据错误个数
if (comboBox1.Text.Trim() == "奇校验")
{
jo = 1;
}
else
{
jo = 0;
}
for (int i = 0; i < 100; i++)
{
string n = (i + 1).ToString(); //序号
jy_r_string[i] = GetNum_jy(jo, bin_r_string[i]);//计算得出校验码
ListViewItem lvi2 = new ListViewItem(n);
lvi2.SubItems.Add(bin_r_string[i]);
lvi2.SubItems.Add(jy_string[i]);
lvi2.SubItems.Add(jy_r_string[i]);
if (jy_string[i] != jy_r_string[i]) //校验位错误
{
lvi2.ForeColor = Color.Red;
jy_c++;
}
else if(bin_string[i] != bin_r_string[i] && jy_string[i] == jy_r_string[i]) //数据错误
{
lvi2.ForeColor = Color.Blue;
bin_c++;
sum_right++;
}
else
{
lvi2.ForeColor = Color.Green;
sum_right++;
}
this.listView2.Items.Add(lvi2);
}
this.listView2.EndUpdate();
this.textBox1.Clear();
this.textBox1.Text = ("共传输数据100个,检测通过数据" + sum_right + "个,数据错误" + jy_c + "个,未检测出的错误" + bin_c + "个,出错率" + (jy_c + bin_c) + "%");
}
6.2.5奇偶校验页面
可以选择奇校验或偶校验
正确的数据标为绿色,未检测出的错误数据标为蓝色,检测出的错误数据标为红色。
6.3 CRC冗余校验
6.3.1被除数赋值函数
//为被除数赋初值
private void Get_bcs(char[] bin_char, char[] bcs)
{
for (int j = 0; j < 8 + xl_length; j++)
{
if (j < 8)
{
bcs[j] = bin_char[j];
}
else
{
bcs[j] = '0';
}
}
}
6.3.2取余运算(计算校验位)函数
//取余运算
private string Quyu(char[] bcs, char[] xl_char)
{
int count = 0; //用于记录被除数位数
char[] jy_char = new char[8];
for (int j = 0; j < 8 + xl_length-1; j++)
{
for(int k = j; k < 8 + xl_length-1; k++)
{
//进行除法
if (bcs[k] == '0' && count == 0)
{
j = k+1;
continue;
}
else
{
if (bcs[k] != xl_char[count])
{
bcs[k] = '1';
}
else
{
bcs[k] = '0';
}
count++;
}
//完成一次除法,归零,进行下一次除法
if (count == xl_length)
{
//判断本次除法过后是否有余数
for (int i = j + 1; i < 8 + xl_length - 1; i++)
{
//判断该位是否为0,并且不是最后一位
if (bcs[i] == '0' && i < 8 + xl_length - 2)
{
continue;
}
//若该位为0,或该位为最后一位
else
{
if ((8 + xl_length - 1) - i < xl_length)
{
int length = (8 + xl_length - 1) - i;//余数位数
if(length == xl_length-1) //余数位数刚好为校验位数时
{
for(int x = 0; x < length; x++)
{
jy_char[x] = bcs[i];
i++;
}
break;
}
else //余数位数少于校验位数时
{
for (int x = 0; x < xl_length-1; x++)
{
if(x+1 > xl_length-1 - length)
{
jy_char[x] = bcs[i];
i++;
}
else
{
jy_char[x] = '0';
}
}
break;
}
}
else
{
if (i == 8 + xl_length - 2)
{
for (int x = 0; x < xl_length - 1; x++)
{
jy_char[x] = '0';
}
}
break;
}
}
}
count = 0;
break;
}
}
if(jy_char[0] == '0' || jy_char[0] == '1')
{
break;
}
}
string jy_char_string = new string(jy_char);
return jy_char_string;
}
6.3.3模拟干扰函数
//模拟干扰
private void Ganrao(string[] bin_r_string)
{
int num_c_sum = new Random().Next(0, 10); //出错总数
Random ran = new Random(unchecked((int)DateTime.Now.Ticks));
for (int i = 0; i < num_c_sum; i++)
{
int num_c = ran.Next(0, 100); //出错的数
int num_c_count = ran.Next(1, 5); //出错位数
int c1 = ran.Next(8); //出错的第一位
int c2 = ran.Next(8); //出错的第二位
int c3 = ran.Next(8); //出错的第三位
int c4 = ran.Next(8); //出错的第四位
char[] a = bin_r_string[num_c].ToCharArray();
//第一位出错
if (a[c1] == '0')
{
a[c1] = '1';
}
else
{
a[c1] = '0';
}
//第二位出错
if (num_c_count > 1)
{
if (a[c2] == '0')
{
a[c2] = '1';
}
else
{
a[c2] = '0';
}
}
//第三位出错
if(num_c_count > 2)
{
if (a[c3] == '0')
{
a[c3] = '1';
}
else
{
a[c3] = '0';
}
}
//第四位出错
if(num_c_count > 3)
{
if (a[c4] == '0')
{
a[c4] = '1';
}
else
{
a[c4] = '0';
}
}
bin_r_string[num_c] = new string(a);
}
}
6.3.4 计算校验位函数
//计算校验位
private void button2_Click(object sender, EventArgs e)
{
if(textBox1.Text == "请输入二进制序列")
{
MessageBox.Show("请输入校验序列");
}
else
{
xl_string = textBox1.Text; //校验序列
char[] xl_char = xl_string.ToCharArray();
xl_length = xl_char.Length; //序列长度
char[] bcs = new char[8 + xl_length]; //被除数
this.listView1.BeginUpdate();
this.listView1.Items.Clear();
for (int i = 0; i < 100; i++)
{
string n = (i + 1).ToString(); //序号
char[] bin_char = bin_string[i].ToCharArray();
Get_bcs(bin_char, bcs); //实现当前二进制数的左移,获取被除数
jy_string[i] = Quyu(bcs, xl_char); //取余运算
ListViewItem lvi = new ListViewItem(n);
lvi.SubItems.Add(bin_string[i]);
lvi.SubItems.Add(jy_string[i]);
this.listView1.Items.Add(lvi);
}
this.listView1.EndUpdate();
}
}
6.3.5 CRC冗余校验页面
正确的数据标为绿色,检测出的错误数据标为红色。
6.4 海明校验
6.4.1 返回校验位(P5-P1)函数
//只返回校验位
public string jy(int[] P, int[] D, char[] bin)
{
int j = 7;
for(int i = 0; i < 8; i++)
{
D[i] = Convert.ToInt32(bin[j]) - 48;
j--;
}
P[0] = D[6] ^ D[4] ^ D[3] ^ D[1] ^ D[0];
P[1] = D[6] ^ D[5] ^ D[3] ^ D[2] ^ D[0];
P[2] = D[7] ^ D[3] ^ D[2] ^ D[1];
P[3] = D[7] ^ D[6] ^ D[5] ^ D[4];
P[4] = P[3] ^ P[2] ^ P[1] ^ P[0] ^ D[7] ^ D[6] ^ D[5] ^ D[4] ^ D[3] ^ D[2] ^ D[1] ^ D[0];
string a = "";
a += Convert.ToString(P[0]);
a += Convert.ToString(P[1]);
a += Convert.ToString(P[2]);
a += Convert.ToString(P[3]);
a += Convert.ToString(P[4]);
return a;
}
6.4.2 返回发生数据函数
//返回待发送数据
public string data_jy(int[] P, int[] D, char[] bin)
{
string a = Convert.ToString(P[4]);
for (int i = 7; i >= 4; i--)
{
a += Convert.ToString(D[i]);
}
a += Convert.ToString(P[3]);
for (int i = 3; i >= 1; i--)
{
a += Convert.ToString(D[i]);
}
a += Convert.ToString(P[2]);
a += Convert.ToString(D[0]);
a += Convert.ToString(P[1]);
a += Convert.ToString(P[0]);
return a;
}
6.4.3 返回发送后校验码(S5-S1)函数
//返回发送后校验位
public string jy_r(int[] H, int[] S, char[] data)
{
int j = 12;
for (int i = 0; i < 13; i++)
{
H[i] = Convert.ToInt32(data[j]) - 48;
j--;
}
S[0] = H[0] ^ H[10] ^ H[8] ^ H[6] ^ H[4] ^ H[2];
S[1] = H[1] ^ H[10] ^ H[9] ^ H[6] ^ H[5] ^ H[2];
S[2] = H[3] ^ H[11] ^ H[6] ^ H[5] ^ H[4];
S[3] = H[7] ^ H[11] ^ H[10] ^ H[9] ^ H[8];
S[4] = H[0] ^ H[1] ^ H[2] ^ H[3] ^ H[4] ^ H[5] ^ H[6] ^ H[7] ^ H[8] ^ H[9] ^ H[10] ^ H[11] ^ H[12];
string c = "";
for (int i = 4; i >= 0; i--)
c += Convert.ToString(S[i]);
return c;
}
6.4.4模拟干扰函数
private void Ganrao(string[] data_r_string)
{
int num_c_sum = new Random().Next(0, 10); //出错总数
Random ran = new Random(unchecked((int)DateTime.Now.Ticks));
for (int i = 0; i < num_c_sum; i++)
{
int num_c = ran.Next(0, 100); //出错的数
int c1 = ran.Next(13); //出错的位
char[] a = data_r_string[num_c].ToCharArray();
if (a[c1] == '0')
{
a[c1] = '1';
}
else
{
a[c1] = '0';
}
data_r_string[num_c] = new string(a);
}
}
6.4.5纠正数据函数
//校正数据
private string jz(string data_r_string, char[] jy_s)
{
string data_jz;
int x = 12;
char[] data_jz_char = data_r_string.ToCharArray();
for(int i = 1; i < 5; i++)
{
if(jy_s[i] == '1')
{
switch (i)
{
case 1:
x -= 8;
break;
case 2:
x -= 4;
break;
case 3:
x -= 2;
break;
case 4:
x -= 1;
break;
}
}
}
//纠正数据
if (x < 13 && data_jz_char[x + 1] == '1')
{
data_jz_char[x + 1] = '0';
}
else if(x < 13 && data_jz_char[x + 1] == '0')
{
data_jz_char[x + 1] = '1';
}
data_jz = new string(data_jz_char);
return data_jz;
}
6.4.6数据校验函数
//数据校验
private void button4_Click(object sender, EventArgs e)
{
int item = 0;
int[] H = new int[13];
int[] S = new int[5];
int sum_right = 0; //记录正确的数据个数
int jy_c = 0; //记录错误个数
//将初始值赋值到受干扰数组中
for (int i = 0; i < 100; i++)
{
data_r_string[i] = data_string[i];
}
Ganrao(data_r_string); //模拟干扰
this.listView2.BeginUpdate();
this.listView2.Items.Clear();
for (int i = 0; i < 100; i++)
{
string n = (i + 1).ToString(); //序号
char[] data_char = data_string[i].ToCharArray();
char[] data_r_char = data_r_string[i].ToCharArray();
jy_r_string[i] = jy_r(H, S, data_r_char);
ListViewItem lvi2 = new ListViewItem(n);
lvi2.SubItems.Add(data_r_string[i]);
lvi2.SubItems.Add(jy_r_string[i]);
char[] jy_s = jy_r_string[i].ToCharArray();
if (jy_s[0] == '1')
{
lvi2.ForeColor = Color.Red;
c[i] = "是"; //S5=1
item = 0;
}
else
{
item = 1;
}
if (item == 0)
{
jy_c++;
}
else
{
c[i] = "否"; //S5=0
lvi2.ForeColor = Color.Green;
sum_right++;
}
lvi2.SubItems.Add(c[i]);
this.listView2.Items.Add(lvi2);
}
this.listView2.EndUpdate();
this.textBox1.Clear();
this.textBox1.Text = ("共传输数据100个,检测通过数据" + sum_right + "个,数据错误" + jy_c + "个,出错率" + jy_c + "%");
}
6.4.7海明校验页面
7.实验结果
使用C#可视化实现了随机生成二进制数,奇偶校验,CRC冗余校验,海明码校验。