**
基于查询二进制树的防冲突算法的研究和改进
**
摘要:针对射频识别(RFID)系统中多个标签同时与读写器进行数据交换时引起的冲突问题,提出了一种改进型的基于二进制树的防冲突算法。该算法在原有的二进制树防冲突算法的基础上修改阅读器每次请求增加的二进制数的位数,有效地降低了阅读器请求的次数和标签冲突的概率,提高了标签识别效率。仿真结果表明,相对于传统的二进制树防冲突算法而言,提出的算法在读写器请求次数和标签识别量上有了一定的提高,尤其在标签数量较多时,其效果更为显著。
关键词:射频识别;防冲突;二进制搜索树,阅读器
1 引言
射频识别技术(Radio Frequency Identification,RFID)是一种非接触式的自动识别技术。相对于传统的识别技术而言,射频识别技术具有读写速度快,安全性高,应用领域广等优点,因而在自动零售管理、接入控制系统、物流管理等方面有着广泛的应用。目前在同一个RFID系统中所有的电子标签通常共享相同频段的无线信道,当多个电子标签同时向读写器发送信号时,不同标签所发送的信息就会发生干扰,以致读写器不能及时准确地识别出每个电子标签的信息,从而产生了RFID电子标签冲突。防冲突算法就是解决RFID系统中多标签冲突问题的有效方法之一。因此设计一种高效的多标签防冲突算法是当前RFID系统进行广泛应用的主要难题和瓶颈所在。
RFID 系统中的防冲突算法主要有两大类:一类是基于ALOHA算法的,另一类是基于二进制树算法的。基于ALOHA的防冲突算法主要是通过给冲突区域内标签分配随机的发送时隙来减小不同标签发生冲突的可能性进而达到防冲突的目的。该类算法的优点是操作简单,应用性强等,但缺点是随机性大、吞吐量低,并且在应用中随着标签数量的扩大性能将会急剧恶化,甚至还会出现“标签饿死问题”。基于二进制树的防冲突算法主要是通过将冲突区域内标签不断地划分为更小的子集的方式来解决多个标签的冲突问题的。该类算法的电路实现比ALOHA类算法稍复杂,但因其具有算法识别率较高,吞吐量大等优点而被广泛应用于RFID系统中。在基于二进制树算法中我们组发现阅读器请求比特串的时候出现这样一个规律,每次请求时通过新增加一位二进制数字作为新的比特串。于是,我们设想,假如每次请求时都增加两位二进制数会不会使识别效率更高?我们猜想此时的查询相当于四叉树,二叉树一旦冲突,冲突可能有00、01、10、11,但是实际上的冲突可能没有四种情况,可能只是两种、三种,那么这样的话,按最坏情况,肯定是比二叉树效率低,但按照最好的情况来看,可能就要好一些。在此基础上我们对此缺点进行了优化,并提出一种基于查询二进制树的防冲突算法的改进算法。
2 算法原理和概述
2.1查询二进制树的防冲突算法
在查询二进制树算法中标签只需要根据阅读器广播的标识符前缀作比较,标签内部不需要标签维持任何状态。阅读器维持一个二进制前缀,初始值为0。每一个时隙开始时,阅读器广播该二进制前缀,标签将自己的标识符号前几位与此进制前缀进行比较。若相同则该标签发送标识符号。否则,标签保持沉默。如果阅读器探测到有冲突发生,则在下次查询中将原来的二进制前缀后面增加0或1,重新查询。阅读器重复以上过程,直到识别完所有的标签。
整个识别过程就像是根据标签的表示符号建立一棵二叉树,该二叉树又被称为查询二叉树。
下面给出了一个具体的例子来描述查询二进制树的执行过程,其中六个标签的ID号分别是{0010、0011、1001、1000、1101},识别过程如下:
①阅读器首先发送请求比特串S=“0”,并将请求比特串“1”压入堆栈中。这时,ID为0010和0011的标签,它们ID的第一个比特与清求比特串相同。因而,这两个标签同时相应阅读器的请求,产生冲突。
②阅读器发送一个较长的请求比特串S=“00”,并将比特串“01”压入堆栈,这时,ID为0010和0011的标签同时响应阅读器的请求,产生冲突。
③阅读器发送一个更长的请求比特串S=“000”,并将“001”压入堆栈,这时,没有任何一个标签的ID的前缀信息能够匹配比特串S,因而没有标答响应。
④由于上一步没有标签响应,因此阅读器从堆栈中弹出比特串“001”,并发送“001”作为请求比特串。这时,ID为0010和0011的标签同时响应阅读器的请求,产生冲突。
⑤阅读器发送请求比特串S=“0010”,并将“011”压以堆栈。这时,只有ID为0010的标签响应阅读器的请求,发送自身的ID给阅读器,因而被阅读器成功识别。
⑥由于上一步成功识别了一个标签,阅读器从堆栈中弹出比特串“0011”作为请求比特串。这时,只有ID为0011的标签响应阅读器的请求,因而被阅读器成功识别。
上述识别过程不断重复,直到堆栈为空为止。此时,所有的标签均已被成功识别。
2.2改进后的算法理论分析
阅读器首先发送请求比特串S=“00”,此时的比特串两位相当于上述算法的一位,比特串的增长也是两位一组增长,此时的两位查询相当于四叉树,二叉树发生冲突时,要么是0要么是1,而四叉树发生一旦冲突,冲突可能有00、01、10、11,但是实际上的冲突可能没有四种情况,查询时,需要判断冲突的后两位到底是哪种情况,可能只是两种,三种,那么这样的话,就会少一种情况。按最坏情况,肯定是比二叉树效率低,但按照最好的情况来看,可能就要好一些。
3两种算法的性能比较和分析
保持识别的总次数一定,分别测试识别总数为1000,2000,3000,4000,5000时改进前和改进后的标签识别数,由表或图可知,改进前的识别标签数少于改进后的标签识别数,由此可以说明,改进后的算法在标签识别量上有了一定的提高,尤其在标签数量较多时,其效果更为显著。
本文在对现有的查询二进制树的防冲突算法的研究上提出了一种改进算法,该算法集合了查询二进制树的防冲突算法的优点,即在降低阅读器识别标签次数的基础上提高了识别效率。通过实验仿真可以看出,该改进二进制树算法在搜索次数方面和识别效率方面都有一定的改善,尤其是在标签数量增加时,性能优化会更明显,为物联网的大量标签识别提供了理论依据和实际探索。
package p1;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class CreatCode {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
Random rd=new Random();
for(int i=0;i<5000;i++) {
String s="";
for(int j=0;j<16;j++) {
s=s+rd.nextInt(2);
}
list.add(s);
}
System.out.println(list.size());
for(int i=0;i<list.size()-1;i++) {
for(int j=i+1;j<list.size();j++) {
while(list.get(i).equals(list.get(j))) {
list.remove(j);
}
}
}
System.out.println(list.size());
try {
File file=new File("D:/2.txt");
FileWriter fr=new FileWriter(file,true);
for(int i=0;i<list.size();i++) {
fr.write(list.get(i)+"\n");
}
fr.flush();
fr.close();
}catch (Exception e) {
}
}
}
改进前:
package p1;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
public class Main {
// 读取文件中的ID存入列表
public List<String> readFile(String string) {
List<String> list = new ArrayList<String>();
try {
FileReader fr = new FileReader(string);
BufferedReader br = new BufferedReader(fr);
String s = "";
while ((s = br.readLine()) != null) {
list.add(s);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
// 将二进制前缀与列表中的ID进行比较
public int seek(String sign, List<String> list) {
int count = 0;
int value = 0;
String first = "";// 记录识别出第一个标签的id;
int f=list.size();
for (int i = 0; i <f; i++) {
if (list.get(i).substring(0, sign.length()).equals(sign)) {
count++;
if (count == 1) {
first = list.get(i);
}
}
}
if (count == 0) {
System.out.print("发出信号为 " + sign + " 无响应");
} else if (count == 1) {
System.out.print("发出信号为 " + sign + " 识别成功");
list.remove(first);
value = 1;
} else {
value = 2;
System.out.print("发出信号为 " + sign + " 冲突个数" + count);
}
return value;
}
public static void main(String[] args) {
Main m = new Main();
List<String> list = m.readFile("D:/1.txt");
List<String> signlist = new ArrayList<String>();
String sign = "";// 二进制前缀
int value = 0;// 返回值
int time = 0;// 次数
// signlist.add( sign + "00");
// signlist.add( sign + "01");
signlist.add( sign + "0");
signlist.add( sign + "1");
int success = 0;// 成功个数
while (signlist.size()> 0) {
sign = signlist.get(0);
value = m.seek(sign, list);
time++;
signlist.remove(sign);
switch (value) {
case 0:// 无响应
break;
case 1:// 识别成功
success++;
break;
case 2:
signlist.add(0, sign + "0");
signlist.add(1, sign + "1");
// signlist.add(2, sign + "10");
// signlist.add(3, sign + "11");
break;
}
System.out.println(" 当前成功识别总数为:" + success);
}
System.out.println("识别次数为" + time + "次,标签总数为:" + success + " 识别完成!");
}
}
改进后:
package p1;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Stack;
public class Main {
// 读取文件中的ID存入列表
public List<String> readFile(String string) {
List<String> list = new ArrayList<String>();
try {
FileReader fr = new FileReader(string);
BufferedReader br = new BufferedReader(fr);
String s = "";
while ((s = br.readLine()) != null) {
list.add(s);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
// 将二进制前缀与列表中的ID进行比较
public String[] seek(String sign, List<String> list) {
Set<String> conSet = new HashSet<>();
// values[0] 放置 count的值, 后面放置冲突的位
String[] values = new String[5];
int count = 0;
int value = 0;
String first = "";// 记录识别出第一个标签的id;
int f = list.size();
for (int i = 0; i < f; i++) {
if (list.get(i).substring(0, sign.length()).equals(sign)) {
count++;
// 统计引起冲突的位
if (list.get(i).length() > sign.length() + 2) {
conSet.add(list.get(i).substring(sign.length(), sign.length() + 2));
}
if (count == 1) {
first = list.get(i);
}
}
}
int len = 1;
for (String str : conSet) {
System.out.println("con: " + str);
values[len++] = str;
}
if (count == 0) {
System.out.print("发出信号为 " + sign + " 无响应");
} else if (count == 1) {
System.out.print("发出信号为 " + sign + " 识别成功");
list.remove(first);
value = 1;
} else {
value = 2;
System.out.print("发出信号为 " + sign + " 冲突个数" + count);
}
values[0] = String.valueOf(value);
return values;
}
public static void main(String[] args) {
Main m = new Main();
List<String> list = m.readFile("D:/2.txt");
List<String> signlist = new ArrayList<String>();
String sign = "";// 二进制前缀
String[] values = new String[5];// 返回值
values[0] = "0";
int time = 0;// 次数
signlist.add(sign + "00");
signlist.add(sign + "01");
signlist.add(sign + "10");
signlist.add(sign + "11");
int success = 0;// 成功个数
while (signlist.size()>0) {
sign = signlist.get(0); // signlist.get(0);
values = m.seek(sign, list);
time++;
signlist.remove(sign);
switch (values[0]) {
case "0":// 无响应
break;
case "1":// 识别成功
success++;
break;
case "2":
for (int i = 1; i < values.length && values[i] != null; i++) {
System.out.println("values:" + values[i]);
signlist.add(i-1, sign + values[i]);
}
// 使用下面,可以识别全部标签
// signlist.add(0, sign + "00");
// signlist.add(1, sign + "01");
// signlist.add(2, sign + "10");
// signlist.add(3, sign + "11");
break;
}
System.out.println(" 当前成功识别总数为:" + success);
}
System.out.println("识别次数为" + time + "次,标签总数为:" + success + " 识别完成!");
}
}