本篇博客用于记录学习和使用github程序包Gen2-UHF-RFID-Reader的过程。出错的地方还望大家指正。
使用平台:ubuntu16.04 UHD3.14.0.HEAD-0-g6875d061 gnuradio3.7.10.1 USRP N210(SBX子板)
本篇详细分析global_vars.h文件。
global_var.h文件里声明了系统中所需要的全局变量及常量。下面逐个分析各变量:
enum STATUS {RUNNING, TERMINATED}; //系统状态有运行、停止两种
enum GEN2_LOGIC_STATUS {SEND_QUERY, SEND_ACK, SEND_QUERY_REP, IDLE, SEND_CW, START, SEND_QUERY_ADJUST, SEND_NAK_QR, SEND_NAK_Q, POWER_DOWN}; //逻辑状态:发送query/query_rep/query_adjust/ack/nak_qr/nak_q,闲置状态,开始状态,掉电状态
enum GATE_STATUS {GATE_OPEN, GATE_CLOSED, GATE_SEEK_RN16, GATE_SEEK_EPC}; //gate模块状态:打开、关闭、查找RN16、查找EPC
enum DECODER_STATUS {DECODER_DECODE_RN16, DECODER_DECODE_EPC}; //Decoder模块状态:解码RN16,解码EPC
枚举类型enum变量共四个,用于记录系统及各模块的状态(所处盘存周期阶段),系统的运行是以各模块间状态的变化为基础的。
struct READER_STATS
{
int n_queries_sent; //已经发送的query数量
int cur_inventory_round; //当前盘存周期数
int cur_slot_number; //当前所处时隙
int max_slot_number; //最大的时隙数
int max_inventory_round; //最大盘存周期数
int n_epc_correct; //正确解码epc的个数
std::vector<int> unique_tags_round; //该信息最终未打印
std::map<std::string,int> tag_reads; //存储标签EPC和正确解码次数
struct timeval start, end; //时间变量,用于计算程序运行用时
};
struct变量READER_STATS用于运行时数据统计。修改了tag_reads的类型std::map<int,int>为std::map< std::sting,int>类型,以达到存储真实epc的目的。
struct READER_STATE
{
STATUS status;
GEN2_LOGIC_STATUS gen2_logic_status;
GATE_STATUS gate_status;
DECODER_STATUS decoder_status;
READER_STATS reader_stats;
std::vector<float> magn_squared_samples; // used for sync
int n_samples_to_ungate; // used by the GATE and DECODER block
};
struct变量READER_STATE用于整合记录系统状态。在各模块状态外,增加了用于同步的变量magn_squared_samples和Gate模块与Decoder模块共同使用变量n_sample_to_ungate。
// Fixed number of slots (2^(FIXED_Q))
const int FIXED_Q = 0;
// Termination criteria
// const int MAX_INVENTORY_ROUND = 50;
const int MAX_NUM_QUERIES = 100; // Stop after MAX_NUM_QUERIES have been sent
// valid values for Q
const int Q_VALUE [16][4] =
{
{0,0,0,0}, {0,0,0,1}, {0,0,1,0}, {0,0,1,1},
{0,1,0,0}, {0,1,0,1}, {0,1,1,0}, {0,1,1,1},
{1,0,0,0}, {1,0,0,1}, {1,0,1,0}, {1,0,1,1},
{1,1,0,0}, {1,1,0,1}, {1,1,1,0}, {1,1,1,1}
};
const bool P_DOWN = false;//规定了系统处于非掉电状态,如需更改,则需要更改后续代码中所有关于P_DOWN注释代码
定义系统工作时时隙数(FIXED_Q)、最大发送queries数(MAX_NUM_QUERIES)、合理的槽计数器参数(Q_VALUE),
Q值:当Q=0时,tag选择该时隙响应;Q值可以通过命令控制;合理的FIXED_Q值可有效减少冲突概率。
// Duration in us
const int CW_D = 250; // Carrier wave
const int P_DOWN_D = 2000; // power down
const int T1_D = 240; // Time from Interrogator transmission to Tag response (250 us)
const int T2_D = 480; // Time from Tag response to Interrogator transmission. Max value = 20.0 * T_tag = 500us
const int PW_D = 12; // Half Tari
const int DELIM_D = 12; // A preamble shall comprise a fixed-length start delimiter 12.5us +/-5%
const int TRCAL_D = 200; // BLF = DR/TRCAL => 40e3 = 8/TRCAL => TRCAL = 200us
const int RTCAL_D = 72; // 6*PW = 72us
定义基本单元的持续时间。
T1_D:从询问机发出信号到标签响应的时间,典型值为MAX(RTcal,10Tpri),其中Tpri为连接脉冲重复间隔,与链路速率BLF成倒数关系。
T2_D:从标签响应到询问机传输的时间,最大值为20Tpri
PW_D:因后续需用一半的Tari,为减少运算难度,定义了Half Tari值,其中Tari为询问机到标签发信时数值为0的基准时间间隔。
TRCAL_D:T=>R校准,根据BLF=DR/TRCAL得到
RTCAL_D:R=>T校准,规定2.5Tari——3Tari,本系统选择3Tari,即6PW_D
下图为协议对时间的规定与解释:
const int NUM_PULSES_COMMAND = 5; // Number of pulses to detect a reader command
const int NUMBER_UNIQUE_TAGS = 100; // Stop after NUMBER_UNIQUE_TAGS have been read
系统可以同时读取多个标签,最大数量为NUMBER_UNIQUE_TAGS,NUM_PULSES_COMMAND为探测reader命令的脉冲数。
// Number of bits
const int PILOT_TONE = 12; // 导频音,可选
const int TAG_PREAMBLE_BITS = 6; // Number of preamble bits
const int RN16_BITS = 17; // Dummy bit at the end
const int EPC_BITS = 129; // PC + EPC + CRC16 + Dummy = 6 + 16 + 96 + 16 + 1 = 135
const int QUERY_LENGTH = 22; // Query length in bits
定义了系统组成部分的bit数:
PILOT_TONE:导频音位数,可选。TRest=0时,无导频音,TRest=1时,有导频音,为12位"0"。
TAG_PREAMBLE_BITS:标签发送信号时,前导码为6为,如需导频音,则跟在导频音后。
RN16_BITS:16位随机数,外加一位结束位。
EPC_BITS:16位PC(协议控制位),96位EPC,16位CRC校验,1位结束位。整个EPC_BITS跟在6位前导码之后。
QUERY_LENGTH:query长度为22位,包括Query命令标识(4位)+DR(1位)+M(2位)+TRest(1位)+Sel(2位)+Session(2位)+Target(1位)+Q(4位)+CRC(5位)
const int T_READER_FREQ = 40e3; // T=>R链路速率,BLF = 40kHz
const float TAG_BIT_D = 1.0/T_READER_FREQ * pow(10,6); // Duration in us
const int RN16_D = (RN16_BITS + TAG_PREAMBLE_BITS) * TAG_BIT_D;
const int EPC_D = (EPC_BITS + TAG_PREAMBLE_BITS) * TAG_BIT_D;
计算了发送1bit数据、RN16(17+6bits)、EPC(6+129bits)所需时间,单位为微秒。
// Query command
const int QUERY_CODE[4] = {1,0,0,0};
const int M[2] = {0,0};
const int SEL[2] = {0,0};
const int SESSION[2] = {0,0};
const int TARGET = 0;
const int TREXT = 0;
const int DR = 0;
详细解释query命令:
字段 | 位数 | 描述 |
---|---|---|
command | 4 | “1000” |
DR | 1 | 除法比例位,0:DR=8,1:DR=64/3,用于设置T=>R链路频率。 |
M | 2 | M位,标志了每个符号的副载波周期数,用于选择调制类型与数据速率。00:M=1,FM0基带调制,数据速率BLF(千位/秒);01:M=2,Miller载波调制,数据速率BLF/2(千位/秒);10:M=4,Miller载波调制,数据速率BLF/4(千位/秒);11:M=8,Miller载波调制,数据速率BLF/8(千位/秒)。 |
TRest | 1 | 0:无导频音,1:有导频音(12位前导“0”) |
Sel | 2 | 选择与query命令匹配的标签,00:全部;01:全部;10:~SL;11:SL |
Session | 2 | 选择该盘存周期的通话,00:S0;01:S1;10:S2;11:S3 |
Taeget | 1 | 选择已盘存标记为A或B的标签参与盘存周期,标签在单化后将其从A(B)盘存到B(A)。0:A;1:B |
Q | 4 | 盘存周期的槽数 |
CRC | 5 | 5位循环冗余校验码 |
const int NAK_CODE[8] = {1,1,0,0,0,0,0,0};
// ACK command
const int ACK_CODE[2] = {0,1};
// QueryAdjust command
const int QADJ_CODE[4] = {1,0,0,1};
// 110 Increment by 1, 000 unchanged, 011 decrement by 1
const int Q_UPDN[3][3] = { {1,1,0}, {0,0,0}, {0,1,1} };
// FM0 encoding preamble sequences
const int TAG_PREAMBLE[] = {1,1,0,1,0,0,1,0,0,0,1,1}; //Tag FM0编码前导码
给出NAK、ACK、query_adjust的指令码,以及调制Q值的指令码和Tag FM0编码的前导码序列。
// Gate block parameters
const float THRESH_FRACTION = 0.75;
const int WIN_SIZE_D = 250;
// Duration in which dc offset is estimated (T1_D is 250)
const int DC_SIZE_D = 120;
// Global variable
extern READER_STATE * reader_state;
extern void initialize_reader_state();
最后定义了三个Gate模块中会用到的参数
THRESH_FRACTION:用于判断阈值的评价标准比例
WIN_SIZE_D:计算直流分量时滑动窗口的时间长度
WIN_SIZE_D:估计直流分量的持续时间