%% EPC Gen2 RFID信号解码器 - 完整实现
% 功能:读取RFID标签I/Q信号,进行信号处理和解码,提取EPC码
% 支持:EPC Gen2协议 (ISO/IEC 18000-63)
% 输入:HackRF采集的I/Q数据文件(.raw格式)
% 输出:解码后的EPC码、协议控制字和CRC校验结果
%% 主函数 - 读取数据并启动解码流程
function epcGen2Decoder()
% 参数配置
Fs = 2e6; % 采样率 2 MHz
bitRate = 40e3; % EPC Gen2典型比特率 40 kbps
samplesPerBit = Fs / bitRate;
% 读取原始I/Q数据
filename = 'received.raw'; % 替换为实际文件名
[I, Q] = readIQData(filename, Fs);
% 形成复信号
iqData = complex(I, Q);
% 信号预处理
processedSignal = preprocessSignal(iqData, Fs);
% 检测前导码并同步信号
[syncedSignal, startIdx] = detectPreamble(processedSignal, Fs, bitRate);
% FM0解码
[bits, decodedSymbols] = fm0Decode(syncedSignal, samplesPerBit);
% 解析EPC数据帧
[epc, pc, crcValid] = parseEPCFrame(bits);
% 显示结果
displayResults(epc, pc, crcValid, length(syncedSignal), Fs);
% 可视化信号
visualizeSignals(iqData, processedSignal, syncedSignal, decodedSymbols);
end
%% 读取I/Q数据
function [I, Q] = readIQData(filename, Fs)
fid = fopen(filename, 'rb');
if fid == -1
error('无法打开文件: %s', filename);
end
% 读取1秒数据 (4.2 MiB = 4.2*1024*1024字节)
bytesPerSecond = 4.2 * 1024 * 1024;
rawData = fread(fid, bytesPerSecond, 'int8=>int8');
fclose(fid);
% 分离I/Q通道
I = double(rawData(1:2:end));
Q = double(rawData(2:2:end));
% 确保I和Q数组长度相同
minLen = min(length(I), length(Q));
I = I(1:minLen);
Q = Q(1:minLen);
end
%% 信号预处理
function processedSignal = preprocessSignal(iqData, Fs)
% 1. 带通滤波 (915MHz ± 0.5MHz)
bpFilter = designfilt('bandpassfir', ...
'FilterOrder', 100, ...
'CutoffFrequency1', 914.5e6, ...
'CutoffFrequency2', 915.5e6, ...
'SampleRate', Fs);
filtered = filtfilt(bpFilter, real(iqData));
% 2. 自动增益控制
rmsVal = rms(filtered);
gain = 0.8 / rmsVal; % 目标RMS值为0.8
processedSignal = filtered * gain;
end
%% 前导码检测与信号同步
function [syncedSignal, startIdx] = detectPreamble(signal, Fs, bitRate)
% 生成理想前导码波形 (FM0编码)
preambleBits = [0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,0,1,0,0,0,1,1,1,0]; % EPC Gen2前导码
samplesPerBit = Fs / bitRate;
preambleWave = genFM0Wave(preambleBits, samplesPerBit);
% 互相关检测
[corrVals, lags] = xcorr(signal, preambleWave);
[~, maxIdx] = max(abs(corrVals));
startIdx = lags(maxIdx) + length(preambleWave);
% 提取同步后的信号
if startIdx < 1 || startIdx > length(signal)
error('前导码检测失败,请检查信号质量');
end
% 提取前导码后2ms的信号 (足够解码)
syncedSignal = signal(startIdx:min(startIdx+4000, length(signal)));
end
%% 生成FM0编码波形
function wave = genFM0Wave(bits, samplesPerBit)
wave = [];
for i = 1:length(bits)
if bits(i) == 0
% 比特0: 电平在比特中点翻转
segment = [ones(1, samplesPerBit/2), -ones(1, samplesPerBit/2)];
else
% 比特1: 电平在整个比特周期不变
if i > 1 && wave(end) > 0
segment = -ones(1, samplesPerBit);
else
segment = ones(1, samplesPerBit);
end
end
wave = [wave, segment];
end
end
%% FM0解码
function [bits, sampledSymbols] = fm0Decode(signal, samplesPerBit)
% 时钟恢复 - 使用自相关法
[corrVals, lags] = xcorr(signal);
[~, maxIdx] = max(corrVals);
bestLag = lags(maxIdx);
% 符号采样
startIdx = max(1, round(samplesPerBit/2 + bestLag));
sampledSymbols = signal(startIdx:round(samplesPerBit):end);
% FM0解码
bits = [];
for i = 2:length(sampledSymbols)
% FM0规则:电平变化=0,不变=1
if (sampledSymbols(i) > 0 && sampledSymbols(i-1) < 0) || ...
(sampledSymbols(i) < 0 && sampledSymbols(i-1) > 0)
bits = [bits, 0]; % 过零检测
else
bits = [bits, 1];
end
end
end
%% 解析EPC数据帧
function [epc, pc, crcValid] = parseEPCFrame(bits)
% 帧结构: [前导码(16b) | 协议控制(16b) | EPC码(96b+) | CRC(16b)]
% 检查最小长度
if length(bits) < 128
error('比特流太短(仅%d位),不足完整帧长度', length(bits));
end
% 提取协议控制字 (PC)
pcBits = bits(17:32);
pc = bin2dec(num2str(pcBits));
% 确定EPC长度 (PC的低8位)
epcWordCount = bitand(pc, 255); % 字数量
epcBitsLength = epcWordCount * 16; % 比特长度
% 检查EPC长度是否合理
minEPCBits = 96; % 最小EPC长度 (96位)
maxEPCBits = 496; % 最大EPC长度 (496位)
if epcBitsLength < minEPCBits || epcBitsLength > maxEPCBits
fprintf('警告:EPC长度 %d 位超出正常范围,使用默认96位\n', epcBitsLength);
epcBitsLength = 96;
end
% 提取EPC码
epcStart = 33;
epcEnd = epcStart + epcBitsLength - 1;
if length(bits) < epcEnd + 16
error('比特流太短,不足完整帧长度');
end
epcBits = bits(epcStart:epcEnd);
% 提取CRC
crcBits = bits(epcEnd+1:epcEnd+16);
receivedCRC = bin2dec(num2str(crcBits));
% CRC校验
dataForCRC = [pcBits, epcBits];
computedCRC = crc16(dataForCRC);
% 输出结果
epc = binaryVectorToHex(epcBits);
crcValid = (receivedCRC == computedCRC);
end
%% CRC-16计算函数 (EPC Gen2使用CRC-16-CCITT)
function crc = crc16(data)
crc = 65535; % 初始值 0xFFFF
poly = 4129; % 多项式 0x1021
for i = 1:length(data)
crc = bitxor(crc, bitshift(data(i), 8));
for j = 1:8
if bitand(crc, 32768) % 0x8000
crc = bitxor(bitshift(crc, 1), poly);
else
crc = bitshift(crc, 1);
end
crc = bitand(crc, 65535); % 0xFFFF
end
end
end
%% 二进制向量转十六进制
function hexStr = binaryVectorToHex(binVec)
% 确保长度是4的倍数
padBits = mod(length(binVec), 4);
if padBits > 0
binVec = [zeros(1, 4-padBits), binVec];
end
% 每4位转换为1个十六进制字符
hexStr = '';
for i = 1:4:length(binVec)
nibble = binVec(i:i+3);
decVal = 8*nibble(1) + 4*nibble(2) + 2*nibble(3) + nibble(4);
hexStr = [hexStr, dec2hex(decVal)];
end
end
%% 结果显示
function displayResults(epc, pc, crcValid, sigLength, Fs)
fprintf('\n===== EPC Gen2 RFID标签解码结果 =====\n');
fprintf('信号长度: %d 样本 (%.2f ms)\n', sigLength, sigLength/Fs*1000);
fprintf('协议控制字(PC): %04X\n', pc);
fprintf('EPC码: %s\n', epc);
if crcValid
fprintf('状态: CRC验证成功\n');
else
fprintf('状态: CRC验证失败 - 数据可能损坏\n');
end
end
%% 信号可视化
function visualizeSignals(rawIQ, processed, synced, symbols)
figure('Position', [100, 100, 1000, 800], 'Name', 'EPC Gen2信号分析');
% 原始I/Q信号
subplot(3,2,1);
plot(real(rawIQ(1:2000)));
hold on;
plot(imag(rawIQ(1:2000)));
title('原始I/Q信号 (前2000样本)');
xlabel('样本索引');
ylabel('幅度');
legend('I通道', 'Q通道');
grid on;
% 预处理后信号
subplot(3,2,2);
plot(processed(1:2000));
title('带通滤波后信号');
xlabel('样本索引');
ylabel('幅度');
grid on;
% 同步后信号
subplot(3,2,3);
plot(real(synced));
title('同步后信号');
xlabel('样本索引');
ylabel('幅度');
grid on;
% 频谱分析
subplot(3,2,4);
N = length(synced);
f = linspace(-0.5, 0.5, N)*1e6; % 频率范围 -0.5MHz到0.5MHz
spectrum = abs(fftshift(fft(synced)));
plot(f, 20*log10(spectrum/max(spectrum)));
title('信号频谱');
xlabel('频率 (MHz)');
ylabel('幅度 (dB)');
grid on;
xlim([-0.5, 0.5]);
% 解码符号
subplot(3,2,5);
stem(symbols, 'filled');
title('解码符号');
xlabel('符号索引');
ylabel('幅度');
grid on;
% 比特流
subplot(3,2,6);
bits = fm0Decode(synced, length(synced)/length(symbols));
stem(bits, 'filled');
title('解码比特');
xlabel('比特索引');
ylabel('比特值');
ylim([-0.1, 1.1]);
grid on;
end在此基础上修改