物联网与射频识别技术,课程实验(一)

news2024/12/27 13:12:43

目录

(1)communication.py

(2)Reader.py

(3)Tag.py


实验1—— EPC C1G2标准下的标签状态转换仿真 

实验说明: 利用Python或Matlab模拟C1G2标签的状态转换模型; 程序应能显示标签当前的状态,并能通过键入的不同指令完成状态的转换。

文件结构如下:

(1)communication.py

import sys
from Tag import Tag
from Reader import Reader


def validACK(tagIndex):
    print('有效的的ACK RN16,tag返回EPC,标签变为Acknowledged状态')
    tagArray[tagIndex].setState('Acknowledged')
    return tagArray[tagIndex].returnEPC()


def invalidACK():
    print('无效的ACK RN16,no reply')


def returnHandle(tagIndex):
    tagArray[tagIndex].setState('Open')
    handle = tagArray[tagIndex].returnHandle()
    print('tag返回handle:{},进入{}状态,交出钥匙,接受指令'.format(handle, tagArray[tagIndex].state))
    return handle


def access(command):
    if command == 'read':
        cmd = reader.read(tagArray[tagIndex])
    elif command == 'write':
        cmd = reader.write(tagArray[tagIndex])
    elif command == 'lock':
        cmd = reader.lock(tagArray[tagIndex])
    elif command == 'kill':
        cmd = reader.kill(tagArray[tagIndex])
    return cmd


# tagNum是标签的数目,tagArray用以存储所有标签
tagNum = int(input('please10 input the number of Tag: '))
Q = int(input('please input the Q to decide the maxNum of slot: '))
tagArray = []
tagIndex = 0

for i in range(tagNum):
    tag = Tag()
    tag.endPoint = (2 ** (Q - 1))
    tagArray.append(tag)

reader = Reader()
print('*****************开始通信*****************')
print('\n*****************进入选择阶段*****************')
selectChoice = int(input('输入0选择全部标签,输入1选择奇数号标签,输入2选择偶数号标签: '))
reader.select(tagArray, selectChoice)
print('\n*****************进入盘存阶段*****************')
ans, tagIndex = reader.Query(tagArray)
while ans is None:  # ans非空时代表slot值为0 tag返回一个RN16 此时ans=RN16
    ans, tagIndex = reader.QueryRep(tagArray)
else:
    ACKRN16 = reader.ACK(ans)
    print('ACK返回RN16,判断是否有效进入下一步')
    if ACKRN16 == ans:
        EPC = validACK(tagIndex)
        print('\n*****************进入访问阶段*****************')
        NewRN16 = reader.Req_RN(EPC, ACKRN16)
        if NewRN16 == ACKRN16:
            print('收到有效的RN16,tag将返回handle(新的16位随机数)')
            handle = returnHandle(tagIndex)
            command, returnhandle = reader.Command(handle)
            if returnhandle == handle:
                cmd = access(command)
                while cmd:
                    command, returnhandle = reader.Command(handle)
                    cmd = access(command)
                else:
                    sys.exit(0)
        else:
            print('收到无效的RN16,no reply')

    else:
        invalidACK()

(2)Reader.py

import random

from Tag import Tag

class Reader:
    def __init__(self):
        self.readerID = self.setReaderID()
        self.crush = 0
        self.noRespond = 0
        self.Q = 2

    # 给每一个阅读器设置一个唯一的16位ID
    def setReaderID(self):
        str = ''
        ID = str.join(random.choice('0123456789') for i in range(16))
        return ID

    # 定义阅读器的标签选择规则 tag=0 选择所有标签 tag=1 选择奇数标签 =2选择偶数标签
    def select(self, tagArray, tag=0):
        if tag == 0:
            for i in range(len(tagArray)):
                tagArray[i].selected = True
            print('select阶段, 所有标签全部被选中')
        elif tag == 1:
            for i in range(1, len(tagArray), 2):
                tagArray[i].selected = True
            print('select阶段, 奇数号标签全部被选中')
        else:
            for i in range(0, len(tagArray), 2):
                tagArray[i].selected = True
            print('select阶段, 偶数号标签全部被选中')

    def QueryTagState(self, tagArray):
        cnt, index = 0, 0  # cnt为此刻slot值为0的标签数目,index为可得到回应的标签
        for i in range(len(tagArray)):
            if tagArray[i].slot == 0:
                cnt += 1
                index = i
        if cnt > 1:
            print('多个tag回应, 发生碰撞, 无法识别, 为Arbitrate状态')
            self.crush += 1
            # 碰撞次数大于随即数右端点的一半
            if self.crush > Tag.endPoint / 2:
                self.QueryAdjust()
            return None, index
        elif cnt == 1:
            tagArray[index].setState('Reply')
            print('{}号tag,其ID为{},slot值为0, 回应reader的随机数为{}, tag进入{}状态'.format(index, tagArray[index].id,
                                                                             tagArray[index].returnRN16(),
                                                                             tagArray[index].state))
            return tagArray[index].returnRN16(), index
        else:
            print('无tag回应, 均为Arbitrate状态')
            self.noRespond += 1
            # 无响应次数大于随即数右端点的一半
            if self.noRespond > Tag.endPoint / 2:
                self.QueryAdjust()
            return None, index

    # 阅读器发出查询Query命令,被选择的标签开始置随机数slot
    def Query(self, tagArray):
        print('********发出第一次Query********')
        for i in range(len(tagArray)):
            if tagArray[i].selected == True:
                tagArray[i].setSlot()
                tagArray[i].setState('Arbitrate')
                print('{}号tag,状态为{}'.format(i, tagArray[i].state))

        tag, index = self.QueryTagState(tagArray)
        return tag, index

    def QueryRep(self, tagArray):
        print('********发出QueryRep, 各标签slot值减1, 或恰好有标签响应********')
        for i in range(len(tagArray)):
            if tagArray[i].selected == True:
                tagArray[i].reduceSlot()

        tag, index = self.QueryTagState(tagArray)
        return tag, index

    def QueryAdjust(self, tagArray):
        print('********发出QueryAdjust, 根据碰撞次数和未响应次数调整slot阈值********')
        tagNum = len(tagArray)
        if self.noRespond > tagNum * 2:
            print('等待响应时间过长, {}轮未得到响应, 下调slot阈值'.format(self.noRespond))
            for i in range(tagNum):
                tagArray[i].adjustSlot(tag=False)
            self.noRespond = 0
        elif self.crush > tagNum * 2:
            print('碰撞{}轮, 过于频繁, 上调slot阈值'.format(self.crush))
            for i in range(tagNum):
                tagArray[i].adjustSlot(tag=True)
            self.crush = 0
        else:
            print('无需调整slot阈值, 已碰撞{}次, 等待响应{}轮'.format(self.crush, self.noRespond))

    # 收到标签的RN16 1.返回ACK指令夹带原RN16 或 2.返回ACK指令,但夹带的RN16错误
    def ACK(self, RN16):
        print('我收到了你的RN16{},ACK'.format(RN16))
        return RN16

    # 得到EPC码后 再次请求随机数 RN16为标签第一次返回的随机数
    def Req_RN(self, EPC, RN16):
        print('我收到了你的EPC{}, Req_RN, 请求返回一个新的随机数'.format(EPC))
        return RN16

    # 得到handle后 随机返回一次命令已经确认的handle值
    def Command(self, handle):
        commandSet = ['read', 'write', 'lock', 'kill']
        command = random.choice(commandSet)
        print('发出新命令{}'.format(command))
        return command, handle

    def read(self, tag):
        print('read tag data:')
        print('tagID:{}\n tagEPC:{}\n tagData:{}'.format(tag.id, tag.EPC, tag.data))
        return 1

    def write(self, tag):
        data = input('待写入数据:')
        tag.data = data
        print('写入完成')
        return 1

    def lock(self, tag):
        print('tagID:{}已lock'.format(tag.id))
        return 1

    def kill(self, tag):
        print('tagID:{} killed,访问结束'.format(tag.id))
        return 0

(3)Tag.py

import random

class Tag:
    # 类属性
    endPoint = 4

    def __init__(self):
        self.id = self.setID()
        self.slot = None
        self.state = 'Ready'
        self.EPC = self.setEPC()
        self.selected = False
        self.len = None
        self.sendTime = None
        self.readerNum = None
        self.data = self.initData()

    # 给每一个标签一个唯一ID 生成16位随机数
    def setID(self):
        str = ''
        ID = str.join(random.choice('0123456789') for i in range(16))
        print('初始化标签ID,tagID={}'.format(ID))
        return ID

    # 给每个标签赋值一个给定区间[0,10]的随机数
    def setSlot(self):
        self.slot = random.randint(0, self.endPoint)
        print('随机给定slot值,tagID={}的slot值为{}, tag的右端点是{}'.format(self.id, self.slot, self.endPoint))

    # 收到QueryAdjust就调整区间右端点 根据tag的值来更改 调整槽计数器的范围 True上调 False下调
    def adjustSlot(self, tag=True):
        if tag == True:
            print()
            Tag.endPoint *= 2
        else:
            Tag.endPoint /= 2
        self.setSlot()

    def setLength(self, length):
        """
        function: 设置数据包长度len和对应所需要的花费时间
        :return: NULL
        """
        self.len = length
        self.sendTime = length * 0.5 + 0.1   #数据包发送时间

    # 自减Slot
    def reduceSlot(self):
        self.slot = (self.slot-1+self.endPoint)%self.endPoint

    # 给每个标签赋值一个96位的随机数 即它的EPC码 只初始化一次
    def setEPC(self):
        str = ''
        RN96 = str.join(random.choice('0123456789') for i in range(96))
        return RN96

    # 返回EPC码
    def returnEPC(self):
        return self.EPC

    # 返回16位的随机数 RN16
    def returnRN16(self):
        str = ''
        RN16 = str.join(random.choice('0123456789') for i in range(16))
        return RN16

    # 返回一个新的随机数 即Handle
    def returnHandle(self):
        return self.returnRN16()

    # 改变标签状态
    def setState(self, newState):
        self.state = newState

    def initData(self):
        foodSet = ['奥利奥', '趣多多', '好丽友', '喜之郎', '娃哈哈']
        priceSet = ['10', '15', '21', '8', '29']
        food = random.choice(foodSet)
        price = random.choice(priceSet)
        return '我的存储区里搁了一个{},{}元一个'.format(food, price)


(4)概要介绍

在EPC C1G2协议标准中,标签的行为可以用有限状态机来描述,七个状态。

就绪态(ready state)
        就绪态是标签在通电前所处的状态。标签处于就绪态,不参与询问过程。
一个询问过程由阅读器发出的查询命令引起,由下一个查询命令终止。阅读器通过查询命令获得标签的EPC码。
当标签接收到一个查询命令,离开就绪态。标签从阅读器发送的查询命令中,选择一个参数生成随机数用于计算发送的时隙。如果随机数为0,则标签进入恢复状态。否则标签进入仲裁态。
仲裁态(arbitrate state)
        当标签处于仲裁态时,它将参加这一轮的查询。但由于此时的标签的时隙数不为0,所以标签等待时隙数变为0.当标签的时隙数变为0时,标签进入回复状态。
回复态(reply state)
        当标签需要回复EPC码时,首先进入的是回复态。这时,标签的时隙数为0,标签返回一个16比特的随机数RN16给阅读器。发送RN16是标签发送EPC码给阅读器的第一步。如果标签正确地接收到RN16,它将会发送一个确认命令ACK给标签。在接收RN16的时候,阅读器可能无法正确接收,主要原因有:a.两个或多个标签同时发生RN16给阅读器b.其它射频信号干扰了RN16的传输c.阅读器错过接收RN16的时间。
        如果标签成功接收到来自阅读器的确认命令ACK,标签将会发送它的EPC码,同时发送PC码(描述标签的物理信息)和CRC码(用于错误检测)。
接收到确认命令ACK引起标签从回复态进入确认态。标签处于回复态的时间有限,只有标签发送RN16后,没有接收到阅读器的任何命令的有效时间才处于该状态。此后,标签会自动进入仲裁态。
确认态(acknowledged state)
        当标签发送它的EPC码给阅读器后 ,标签进入确认态。确认态是标签进入访问命令的必经状态。在确认态中,标签不会被杀死。确认态就像回复态一样,有一个计时器,每当接收到一个命令式,计时器将会置位0。如果标签在指定的时间内没有收到来自阅读器的命令,标签将会自动返回仲裁态。
开放态
安全态
杀死态

        杀死操作不能被解除,它将会永远地毁坏标签。 对于一个标签而言,它是在接收到阅读器的正确的密码和杀死命令之后,才会进入杀死态。此后,标签会一直处于杀死态而不是就绪态。当标签进入杀死态,不会再响应阅读器的任何命令。

参考链接:

(24条消息) 标签的状态机_Caramel_biscuit的博客-CSDN博客_在确认态,标签会回复给阅读器pc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习:01 神经网络与激活函数

目前,最广泛使用的定义是Kohonen于1988年的描述: 神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所做出的交互反应。 目录 对神经网络的概述 神经网络的表示 激活函数 为什么激…

2022年总结:从初二学生到算法作者的蜕变之路

目录 一年的创作历程 我和 CSDN 在编程竞赛的合作 About CBC 技术社区的发展 夜跑奇遇 About 博客之星 新年致谢 元旦祝福 一年的创作历程 2022年,这一年对于我来说是十分重要的一年。在这一年里,我作为一名初二在校学生,在CSDN上发布…

【Linux 环境变量】环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数

1.问题:为什么自己写的程序需要加上./才能执行,但是指令可以直接使用,例:ls -al? 因为:不加"./"执行程序的时候会按环境变量PATH里面的各个路径找到就正常执行,找不到就报错&#xff…

SQL笔试题总结

文章目录前言一、列转行题目:将表Student转化为下面的形式展示先放答案逐步剖析二、row_number() over() 的使用题目:统计订单交易表(orders)每个商品交易金额最高的那一条数据先放答案逐步剖析三、逐行累加题目:还是订…

✿✿✿JavaScript --- jQuery框架二

目 录 1.高级事件 (1)浏览器一打开自动触发我们绑定的事件 (2) Trigger 传递数据 (3)自定义事件 (4)trigger 简写方案 (5)triggerHandler() (6)trigger和triggerHandler的区别 (7)on off one 2.动画 (1)显示 隐藏 动画 (2)队列动画 (3)下滑 上卷 (4)淡入淡出…

Nacos启动出现Error creating bean with name ‘memoryMonitor‘ 、‘externalDumpService‘

目录 🧡问题 🧡解决方法 💟这里是CS大白话专场,让枯燥的学习变得有趣! 💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话! 💟好记性不如烂键盘&#x…

WSL2支持systemctl命令

文章目录背景相关知识systemdinit安装方法一:微软官方支持方法(推荐)方法二:安装daemonize实现参考背景 微软官方推出Windows Terminal第一时间,我就安装了这个终端软件。现在GitHub已经有86.8k星,且发布了…

一名普通Java程序员的2022的总结和2023的展望

前言今天是元旦节,也是2023年的第一天,首先祝各位亲朋好友们元旦快乐,在新的一年全家身体康健,诸事顺遂,阖家幸福,最重要的是身体健康,工作顺利,永无BUG永不加班!&#x…

计算机组成原理【1】初识硬件

目录 考点1:硬件发展———————————————————————————— 一.计算机硬件的基本组成 1.早期冯诺依曼机 (1)冯.诺依曼计算机的特点: 2.现代计算机的结构 3.总结图 二.各个硬件的工作原理 1.寄存器MAR,MDR 2.主存…

EMNLP22 外部知识注入:Prompt-Learning for Short Text Classification

Prompt-Learning for Short Text Classification 任务形式:短文本分类问题,但是短文本的短长度、特征稀疏性和高模糊性给分类任务带来了巨大挑战。 1以往的工作,在注入外部信息上 大多数提示学习方法手动扩展标签词或仅考虑类别名称以纳入…

得分_UVa1585分子量_UVa1586数数字_UVa1225周期串_UVa455子序列_UVa10340

目录 P57_习题3-1_得分_UVa1585 P57_习题3-2_分子量_UVa1586 原子数范围0~99 书上给的代码 P57_习题3-3_数数字_UVa1225 P57_习题3-4_周期串_UVa455 P59_习题3-9_子序列_UVa10340 P57_习题3-1_得分_UVa1585 给出一个由O和X组成的串(长度为1~80&a…

网络原理2 TCP协议

TCP协议 文章目录TCP协议TCP的特点TCP的基本特性确认应答机制超时重传机制丢包连接管理机制TCP建立连接---三次握手TCP断开连接---四次挥手滑动窗口机制丢包问题流量控制机制拥塞控制机制延迟应答机制捎带应答机制面向字节流问题TCP中的异常处理程序崩溃了正常关机突然断电关机…

在前端解决跨域

1、环境依赖 C:\Users\cyberzhaohyvm>node -v v14.17.3 C:\Users\cyberzhaohyvm>vue -V vue/cli 5.0.4 2、在项目所在目录,安装axios 进入项目所在目录: D:\01sourcecode\10Tutorial\08Vue\17-2022-12-28-v2\elementui-demo npm install axios …

Redis单线程为什么这么快?

Redis单线程为什么这么快? 第一章 Redis单线程为什么这么快 Redis深度剖析【第一章】Redis单线程为什么这么快?前言一、Redis为什么要使用单线程,而不是多线程?单线程的优势如果Redis使用多线程:既然多线程切换存在消…

【博学谷学习记录】大数据课程-学习第一周总结

Linux服务器 对于Linux操作系统来说,其本身是一个整体,包括Linux内核、系统库和系统程序,Linux内核是其最基础的部分,它实现了对硬件资源的管理,并且提供了使用这些硬件资源的通用接口。 自1991年发布Linux内核来&…

项目实战之旅游网(十四)项目部署-Docker

为了节约资源,在生产环境中我们更多的是使用Docker容器部署SpringBoot应用, 我们要用maven里的docker插件来生成镜像并且远程连接Docker, 开启远程docker服务: # 修改docker配置文件 vim /lib/systemd/system/docker.service 把…

简阅人体姿态估计深度学习方法-simpread-Human Pose Estimation Deep Learning Approach

What is Human Pose Estimation? Human Pose Estimation (HPE) is a way of identifying and classifying the joints in the human body Human Pose Estimation(HPR 人体姿态估计)是一个对人体关节进行识别和分类的方法。 Essentially it is a way to capture a set of co…

Good Bye 2022: 2023 is NEAR C. Koxia and Number Theory

原题链接:Problem - C - Codeforces 题意: 给定一个长度为n的数组,请问是否存在一个数 x ,使得任意两个数 与满足 。若是输出 YES ,反之输出 NO 。 思路: 我们可以发现一个规律: 规律&#…

本周大新闻|沙特PIF再投Magic Leap,周融资超5.1亿美元

本周大新闻,AR方面,OVER推出众包AR地图Map2Earn;AR房产平台homeAR推扫码看房功能;苹果智能指环专利公布,支持手势和触觉反馈。 VR方面,奇遇MIX正式发布;AjnaLens将发布新XR头显;Gen…

Cartesi 2022 年 12 月回顾

查看你不想错过的更新2022 年 12 月 31 日 ,我们将继续保持高昂的建设斗志一直持续到2023年。我们在2022年年底前参加了两次编程马拉松, 并不是一次。我们将 Cartesi 的技术带给了ETH India 活动的2000 多名建设者,我们还与 SuperwomenDAO 合…