stf服务安装后,手机上的手动启用。

本文分享了在使用STF时遇到的诺基亚7Plus手机识别问题及解决方案。通过启动特定的应用和服务,成功使设备在安卓9.0系统下被STF识别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之间搭建stf的时候,我的手机是诺基亚7plus,系统为安卓9.0.发现无法识别到手机,这个时候,就试着启动应用和Activity,然后发现确实可行。

adb shell am start -n jp.co.cyberagent.stf/.IdentityActivity
adb shell am startservice -n jp.co.cyberagent.stf/.Service

global IMAGE_FILE_TO_SEND_FROM_GUI; % 定义通信信道类型:"OverTheAir" 表示通过SDR硬件进行空中传输。 channel = "OverTheAir"; % 根据信道类型设置不同的参数 if strcmpi(channel,"OverTheAir") % 检查信道是否为 "OverTheAir" deviceName = "Pluto"; % 设置SDR设备名称 (例如 ADALM-PLUTO) channelNumber = 10; % 设置WLAN信道号 (例如 5) frequencyBand = 2.4; % 设置工作频段 (例如 2.4 GHz) txGain = 0; % 设置SDR发射增益 (dB) rxGain = 14; % 设置SDR接收增益 (dB) elseif strcmpi(channel,"GaussianNoise") % 检查信道是否为 "GaussianNoise" % 为仿真信道指定接收信号的信噪比 (SNR) SNR = 20; % 设置信噪比 (dB) end % 设置图像绘图句柄 if ~exist('imFig','var') || ~ishandle(imFig) %#ok<SUSENS> % 检查图像窗口变量 'imFig' 是否存在或是否为有效句柄 imFig = figure; % 创建一个新的图形窗口 imFig.NumberTitle = 'off'; % 关闭窗口标题中的序号 (Figure 1) imFig.Name = 'Image Plot'; % 设置窗口标题 imFig.Visible = 'off'; % 初始状态下隐藏窗口 else clf(imFig); % 如果窗口已存在,则清除窗口内容 imFig.Visible = 'off'; % 隐藏窗口 end % 设置频谱分析仪 spectrumScope = spectrumAnalyzer( ... SpectrumType='power-density', ... % 设置频谱类型为功率谱密度 Title='Received Baseband WLAN Signal Spectrum', ... % 设置频谱仪标题 YLabel='Power spectral density', ... % 设置Y轴标签 Position=[69 376 800 450]); % 设置频谱仪窗口位置和大小 [left bottom width height] % 设置用于显示均衡后WLAN符号的星座图查看器 refQAM = wlanReferenceSymbols('64QAM'); % 获取 64-QAM 的参考星座点 constellation = comm.ConstellationDiagram(... Title='Equalized WLAN Symbols',... % 设置星座图标题 ShowReferenceConstellation=true,... % 显示参考星座点 ReferenceConstellation=refQAM,... % 设置参考星座点 Position=[878 376 460 460]); % 设置星座图窗口位置和大小 % --- 获取图像文件名 --- if ~isempty(IMAGE_FILE_TO_SEND_FROM_GUI) && exist(IMAGE_FILE_TO_SEND_FROM_GUI, 'file') fileTx = IMAGE_FILE_TO_SEND_FROM_GUI; fprintf('SDR Script: 接收到来自GUI的文件路径: %s\n', fileTx); else fprintf('SDR Script: 未从GUI接收到有效文件路径,使用默认 peppers.png\n'); fileTx = 'peppers.png'; % 如果全局变量无效,则使用默认值 if ~exist(fileTx,'file') fprintf('错误: 默认图片 peppers.png 也不存在,请检查路径。\n'); return; end end clear global IMAGE_FILE_TO_SEND_FROM_GUI; % 清除全局变量,避免影响下次运行 % 输入图像文件并转换为二进制流 %fileTx = './1_compressed_jpeg_q75.jpg'; % 图像文件名 fData = imread(fileTx); % 从文件读取图像数据 scale = 0.2; % 图像缩放因子 origSize = size(fData); % 获取原始输入图像尺寸 scaledSize = max(floor(scale.*origSize(1:2)),1); % 计算新的图像尺寸 (至少为1x1) % 计算缩放后像素对应的原始图像像素索引 (最近邻插值) heightIx = min(round(((1:scaledSize(1))-0.5)./scale+0.5),origSize(1)); widthIx = min(round(((1:scaledSize(2))-0.5)./scale+0.5),origSize(2)); fData = fData(heightIx,widthIx,:); % 根据计算的索引调整图像大小 imsize = size(fData); % 存储新的图像尺寸 txImage = fData(:); % 将调整大小后的图像数据展平成列向量 % 绘制发射图像 imFig.Visible = 'on'; % 使图像窗口可见 subplot(211); % 选择第一个子图 (2行1列中的第1个) imshow(fData); % 显示调整大小后的发射图像 title('Transmitted Image'); % 设置子图标题: "发射图像" subplot(212); % 选择第二个子图 (2行1列中的第2个) title('Received image appears here...'); % 设置子图标题: "接收图像将显示在此处..." set(gca,'Visible','off'); % 隐藏坐标轴 set(findall(gca, 'type', 'text'), 'visible', 'on'); % 确保标题文本可见 % 准备数据进行传输 msduLength = 2304; % 设置MSDU (MAC Service Data Unit) 长度 (字节) numMSDUs = ceil(length(txImage)/msduLength); % 计算需要的MSDU数量 (向上取整) padZeros = msduLength-mod(length(txImage),msduLength); % 计算最后一个MSDU需要填充的零的数量 txData = [txImage;zeros(padZeros,1)]; % 将图像数据填充零,使其长度为 msduLength 的整数倍 txDataBits = double(int2bit(txData,8,false)); % 将填充后的图像数据 (字节) 转换为双精度比特流 (LSB first) % 将输入数据流分割成片段,并封装成MPDU (MAC Protocol Data Unit) bitsPerOctet = 8; % 定义每个字节的比特数 data = zeros(0,1); % 初始化用于存储所有MPDU比特的变量 for i=0:numMSDUs-1 % 遍历每个MSDU % 提取当前MPDU的图像数据 (字节) frameBody = txData(i*msduLength+1:msduLength*(i+1),:); % 创建MAC帧配置对象,并配置帧类型为数据帧和序列号 cfgMAC = wlanMACFrameConfig(FrameType='Data',SequenceNumber=i); % 生成MPDU (物理层服务数据单元 PSDU) [psdu, lengthMPDU]= wlanMACFrame(frameBody,cfgMAC,OutputFormat='bits'); % 将生成的PSDU比特连接起来,用于后续波形生成 data = [data; psdu]; %#ok<AGROW> % 允许数组在循环中增长 end % 配置WLAN Non-HT (非高吞吐量) 物理层参数 nonHTcfg = wlanNonHTConfig; % 创建Non-HT配置对象 nonHTcfg.MCS = 6; % 设置调制与编码方案 (MCS): 6 (64QAM, 速率 2/3) nonHTcfg.NumTransmitAntennas = 1; % 设置发射天线数量 chanBW = nonHTcfg.ChannelBandwidth; % 获取信道带宽 (例如 'CBW20') nonHTcfg.PSDULength = lengthMPDU; % 设置PSDU长度 (注意:这里使用了最后一个MPDU的长度,假设所有MPDU长度相同) scramblerInitialization = randi([1 127],numMSDUs,1); % 为每个数据包生成随机的加扰器初始值 (1到127之间) osf = 1.5; % 设置过采样因子 sampleRate = wlanSampleRate(nonHTcfg); % 获取标称采样率 (Hz) % 生成基带Non-HT数据包,数据包之间有空闲时间 txWaveform = wlanWaveformGenerator(data,nonHTcfg, ... % 使用数据比特和配置生成波形 NumPackets=numMSDUs, ... % 指定要生成的数据包数量 IdleTime=20e-6, ... % 设置数据包之间的空闲时间 (20 微秒) ScramblerInitialization=scramblerInitialization,... % 指定每个包的加扰器初始值 OversamplingFactor=osf); % 应用过采样因子 % 如果是通过空中传输 if strcmpi(channel,"OverTheAir") % 发射器属性配置 sdrTransmitter = sdrtx(deviceName); % 创建SDR发射器对象 sdrTransmitter.BasebandSampleRate = sampleRate*osf; % 设置基带采样率 (包括过采样) sdrTransmitter.CenterFrequency = wlanChannelFrequency(channelNumber,frequencyBand); % 设置中心频率 sdrTransmitter.Gain = txGain; % 设置发射增益 % 对于 USRP Embedded Series Radio,直接将SDR I/O传递给主机,跳过FPGA if ~strcmpi(deviceName,"Pluto") % 如果设备不是Pluto sdrTransmitter.ShowAdvancedProperties = true; % 显示高级属性 sdrTransmitter.BypassUserLogic = true; % 启用旁路用户逻辑 end fprintf('\nGenerating WLAN transmit waveform:\n'); % 打印提示信息:正在生成WLAN发射波形 % 对归一化信号进行缩放,以避免RF前端饱和 powerScaleFactor = 0.8; % 功率缩放因子 txWaveform = txWaveform.*(1/max(abs(txWaveform))*powerScaleFactor); % 缩放波形,使其最大绝对值不超过 powerScaleFactor % 发射RF波形 (重复发射,直到停止) transmitRepeat(sdrTransmitter,txWaveform); end % 接收处理 if strcmpi(channel,"OverTheAir") % 如果是空中传输信道 sdrReceiver = sdrrx(deviceName); % 创建SDR接收器对象 sdrReceiver.BasebandSampleRate = sdrTransmitter.BasebandSampleRate; % 设置与发射器相同的基带采样率 sdrReceiver.CenterFrequency = sdrTransmitter.CenterFrequency; % 设置与发射器相同的中心频率 sdrReceiver.OutputDataType = 'double'; % 设置输出数据类型为双精度 sdrReceiver.GainSource = 'Manual'; % 设置增益控制源为手动 sdrReceiver.Gain = rxGain; % 设置接收增益 % 对于 USRP Embedded Series Radio 的配置 if ~strcmpi(deviceName,"Pluto") % 如果设备不是Pluto sdrReceiver.ShowAdvancedProperties = true; % 显示高级属性 sdrReceiver.BypassUserLogic = true; % 启用旁路用户逻辑 end % 配置捕获长度为发射信号长度的两倍,以确保按顺序接收PSDU。 % 接收时会移除重复的MAC片段。 sdrReceiver.SamplesPerFrame = 2*length(txWaveform); % 设置每帧捕获的样本数 fprintf('\nStarting a new RF capture.\n'); % 打印提示信息:开始新的RF捕获 rxWaveform = capture(sdrReceiver,sdrReceiver.SamplesPerFrame,'Samples'); % 捕获指定数量的样本 elseif strcmpi(channel,"GaussianNoise") % 如果是高斯噪声信道 % 在发射波形上添加高斯白噪声 (AWGN) rxWaveform = awgn(txWaveform,SNR,'measured'); % 根据指定的SNR添加噪声,'measured'表示先测量信号功率 else % 无损伤信道 (理想信道) rxWaveform = txWaveform; % 接收波形等于发射波形 end % 显示接收信号的频谱 spectrumScope.SampleRate = sampleRate*osf; % 设置频谱仪的采样率 (包含过采样) spectrumScope(rxWaveform); % 将接收波形送入频谱仪进行显示 release(spectrumScope); % 释放频谱仪对象,以便后续可以修改属性或重新使用 % 设计并应用一个FIR滤波器来移除过采样 (降采样) aStop = 40; % 滤波器阻带衰减 (dB) ofdmInfo = wlanNonHTOFDMInfo('NonHT-Data',nonHTcfg); % 获取Non-HT数据部分的OFDM参数 SCS = sampleRate/ofdmInfo.FFTLength; % 计算子载波间隔 (Hz) txbw = max(abs(ofdmInfo.ActiveFrequencyIndices))*2*SCS; % 计算占用带宽 (Hz) [L,M] = rat(1/osf); % 计算速率转换的整数因子 L/M (L=2, M=3 for osf=1.5) maxLM = max([L M]); % L和M中的最大值 R = (sampleRate-txbw)/sampleRate; % 计算归一化半带宽 TW = 2*R/maxLM; % 计算滤波器的归一化过渡带宽 b = designMultirateFIR(L,M,TW,aStop); % 设计多速率FIR滤波器系数 firrc = dsp.FIRRateConverter(L,M,b); % 创建FIR速率转换器对象 rxWaveform = firrc(rxWaveform); % 应用滤波器进行降采样,得到标称采样率的波形 % 初始化接收处理循环变量 displayFlag = false; % 是否显示详细解码信息的标志 rxWaveformLen = size(rxWaveform,1); % 获取降采样后接收波形的长度 searchOffset = 0; % 在波形中搜索数据包的起始偏移量 (样本) ind = wlanFieldIndices(nonHTcfg); % 获取Non-HT PPDU各字段的索引 Ns = ind.LSIG(2)-ind.LSIG(1)+1; % 一个OFDM符号的样本数 (包括循环前缀) % 最小数据包长度定义为10个OFDM符号 (L-STF算2个,L-LTF算2个,L-SIG算1个,至少再加5个数据符号) lstfLen = double(ind.LSTF(2)); % L-STF字段的长度 (样本数) minPktLen = lstfLen*5; % 定义检测所需的最小数据包长度 (约为10个OFDM符号) pktInd = 1; % 初始化检测到的数据包索引 fineTimingOffset = []; % 初始化精细定时偏移 packetSeq = []; % 初始化存储接收到的数据包序列号的数组 rxBit = {}; % 初始化存储接收到的数据比特的单元数组 % EVM (误差向量幅度) 计算器设置 evmCalculator = comm.EVM(AveragingDimensions=[1 2 3]); % 创建EVM计算器,对所有维度求平均 evmCalculator.MaximumEVMOutputPort = true; % 使能输出峰值EVM % 循环处理接收到的波形,搜索并解码WLAN数据包 while (searchOffset+minPktLen)<=rxWaveformLen % 当剩余波形长度足够容纳一个最小数据包时继续搜索 % 1. 包检测:在当前搜索偏移之后查找WLAN包的起始位置 pktOffset = wlanPacketDetect(rxWaveform,chanBW,searchOffset,0.5); % 使用L-STF相关性检测包,阈值0.5 % 调整包偏移量,使其成为相对于整个接收波形起始点的绝对偏移 pktOffset = searchOffset+pktOffset; % 如果未检测到包,或者检测到的包起始点太靠后以至于无法提取L-SIG字段 if isempty(pktOffset) || (pktOffset+double(ind.LSIG(2))>rxWaveformLen) if pktInd==1 % 如果是第一次尝试且未检测到包 disp('** No packet detected **'); % 显示未检测到包的消息 end break; % 退出循环 end % 2. 粗略频率偏移估计与校正 % 提取 Non-HT 字段 (L-STF, L-LTF, L-SIG) 用于粗略频偏估计和符号定时 nonHT = rxWaveform(pktOffset+(ind.LSTF(1):ind.LSIG(2)),:); % 提取 L-STF 到 L-SIG 结束的部分 coarseFreqOffset = wlanCoarseCFOEstimate(nonHT,chanBW); % 使用L-STF估计粗略载波频率偏移 (CFO) nonHT = frequencyOffset(nonHT,sampleRate,-coarseFreqOffset); % 对提取的部分进行粗略频偏校正 % 3. 符号定时估计 fineTimingOffset = wlanSymbolTimingEstimate(nonHT,chanBW); % 使用L-LTF估计符号定时偏移 % 根据符号定时偏移调整数据包的精确起始位置 pktOffset = pktOffset+fineTimingOffset; % 检查调整后的包起始位置是否有效 (不能为负数,且包结束不能超出接收波形) if (pktOffset<0) || ((pktOffset+minPktLen)>rxWaveformLen) searchOffset = pktOffset+1.5*lstfLen; % 更新搜索偏移量,跳过当前检测区域 continue; % 继续下一次循环迭代 end fprintf('\nPacket-%d detected at index %d\n',pktInd,pktOffset+1); % 打印检测到的包序号和起始索引 % 4. 精细频率偏移估计与校正 % 提取前7个OFDM符号的数据 (L-STF, L-LTF, L-SIG, 和后面几个符号),用于格式检测和L-SIG解码 nonHT = rxWaveform(pktOffset+(1:7*Ns),:); nonHT = frequencyOffset(nonHT,sampleRate,-coarseFreqOffset); % 先应用粗略频偏校正 % 提取L-LTF字段 lltf = nonHT(ind.LLTF(1):ind.LLTF(2),:); fineFreqOffset = wlanFineCFOEstimate(lltf,chanBW); % 使用L-LTF估计精细频率偏移 nonHT = frequencyOffset(nonHT,sampleRate,-fineFreqOffset); % 对提取的 nonHT 部分应用精细频偏校正 cfoCorrection = coarseFreqOffset+fineFreqOffset; % 计算总的频率偏移 % 5. 信道估计 lltf = nonHT(ind.LLTF(1):ind.LLTF(2),:); % 重新提取经过精细频偏校正的L-LTF demodLLTF = wlanLLTFDemodulate(lltf,chanBW); % 解调L-LTF得到频域符号 chanEstLLTF = wlanLLTFChannelEstimate(demodLLTF,chanBW); % 使用解调后的L-LTF符号进行信道估计 % 6. 噪声估计 noiseVarNonHT = wlanLLTFNoiseEstimate(demodLLTF); % 使用解调后的L-LTF符号估计噪声方差 % 7. 格式检测 % 使用L-LTF之后的3个OFDM符号进行包格式检测 format = wlanFormatDetect(nonHT(ind.LLTF(2)+(1:3*Ns),:), ... chanEstLLTF,noiseVarNonHT,chanBW); disp([' ' format ' format detected']); % 显示检测到的格式 if ~strcmp(format,'Non-HT') % 如果检测到的不是 Non-HT 格式 fprintf(' A format other than Non-HT has been detected\n'); % 打印消息 searchOffset = pktOffset+1.5*lstfLen; % 更新搜索偏移量 continue; % 继续下一次循环 end % 8. L-SIG 恢复与解码 % 提取 L-SIG 字段并恢复其比特 [recLSIGBits,failCheck] = wlanLSIGRecover( ... nonHT(ind.LSIG(1):ind.LSIG(2),:), ... % 提取L-SIG时域波形 chanEstLLTF,noiseVarNonHT,chanBW); % 使用信道估计和噪声估计进行恢复 if failCheck % 检查L-SIG校验是否失败 (例如奇偶校验错误) fprintf(' L-SIG check fail \n'); % 打印L-SIG校验失败 searchOffset = pktOffset+1.5*lstfLen; % 更新搜索偏移量 continue; % 继续下一次循环 else fprintf(' L-SIG check pass \n'); % 打印L-SIG校验成功 end % 9. L-SIG 信息解析 % 根据解码的L-SIG比特获取包参数 [lsigMCS,lsigLen,rxSamples] = helperInterpretLSIG(recLSIGBits,sampleRate); % 调用辅助函数解析MCS, 长度(字节), 包总样本数 if (rxSamples+pktOffset)>length(rxWaveform) % 检查是否有足够的样本来解码整个包 disp('** Not enough samples to decode packet **'); % 打印样本不足的消息 break; % 退出循环 end % 10. 对整个数据包应用总频率偏移校正 rxWaveform(pktOffset+(1:rxSamples),:) = frequencyOffset(... rxWaveform(pktOffset+(1:rxSamples),:),sampleRate,-cfoCorrection); % 11. 创建接收 Non-HT 配置对象 rxNonHTcfg = wlanNonHTConfig; rxNonHTcfg.MCS = lsigMCS; % 设置从L-SIG解码得到的MCS rxNonHTcfg.PSDULength = lsigLen; % 设置从L-SIG解码得到的PSDU长度 % 获取PPDU内数据字段的索引 indNonHTData = wlanFieldIndices(rxNonHTcfg,'NonHT-Data'); % 12. Non-HT 数据恢复 % 提取数据字段波形,并使用L-LTF的信道估计进行均衡和解码 [rxPSDU,eqSym] = wlanNonHTDataRecover(rxWaveform(pktOffset+... (indNonHTData(1):indNonHTData(2)),:), ... % 提取数据字段时域波形 chanEstLLTF,noiseVarNonHT,rxNonHTcfg); % 使用信道估计、噪声估计和接收配置恢复PSDU比特和均衡后的符号 % 13. 星座图显示 constellation(reshape(eqSym,[],1)); % 显示当前数据包的均衡后符号星座图 release(constellation); % 释放星座图对象 % 14. EVM 计算 refSym = wlanClosestReferenceSymbol(eqSym,rxNonHTcfg); % 找到每个均衡符号最近的理想参考星座点 [evm.RMS,evm.Peak] = evmCalculator(refSym,eqSym); % 计算 RMS EVM 和 Peak EVM % 15. MPDU 解码和MSDU提取 % 尝试解码恢复的PSDU比特流,提取MAC头信息和MSDU (数据载荷) [cfgMACRx,msduList{pktInd},status] = wlanMPDUDecode(rxPSDU,rxNonHTcfg); %#ok<*SAGROW> % 允许单元数组在循环中增长 if strcmp(status,'Success') % 如果解码成功 (包括FCS校验通过) disp(' MAC FCS check pass'); % 打印MAC FCS校验通过 % 存储序列控制信息 (主要是序列号) packetSeq(pktInd) = cfgMACRx.SequenceNumber; % 存储该包的序列号 % 将十六进制字符串格式的MSDU转换为二进制数据流 rxBit{pktInd} = int2bit(hex2dec(cell2mat(msduList{pktInd})),8,false); % 转换为比特流并存储 else % 如果解码失败 if strcmp(status,'FCSFailed') % 如果是FCS校验失败 disp(' MAC FCS check fail'); % 打印MAC FCS校验失败 else % 其他解码失败情况 (理论上FCS可能通过但仍有错) disp(' MAC FCS check pass'); % 假设FCS通过了 (或不关心FCS) end % 由于本示例中没有建模重传,即使FCS校验失败,也尝试提取图像数据(MSDU)和序列号。 % 移除MAC头和FCS,提取MSDU。 macHeaderBitsLength = 24*bitsPerOctet; % MAC头部长度 (比特) fcsBitsLength = 4*bitsPerOctet; % FCS长度 (比特) msduList{pktInd} = rxPSDU(macHeaderBitsLength+1:end-fcsBitsLength); % 提取MSDU比特 (可能包含错误) % 提取并存储序列号 sequenceNumStartIndex = 23*bitsPerOctet+1; % 序列控制字段的起始比特索引 (假设为标准数据帧) sequenceNumEndIndex = 25*bitsPerOctet-4; % 序列控制字段的结束比特索引 (前12比特是序列号) conversionLength = sequenceNumEndIndex-sequenceNumStartIndex+1; % 序列号字段长度 packetSeq(pktInd) = bit2int(rxPSDU(sequenceNumStartIndex:sequenceNumEndIndex),conversionLength,false); % 从比特恢复序列号 % 将提取的 (可能有误的) MSDU 比特流存储起来 rxBit{pktInd} = double(msduList{pktInd}); end % 16. 显示解码信息 (如果 displayFlag 为 true) if displayFlag fprintf(' Estimated CFO: %5.1f Hz\n\n',cfoCorrection); %#ok<*UNRCH> % 显示估计的总CFO disp(' Decoded L-SIG contents: '); % 显示解码的L-SIG内容 fprintf(' MCS: %d\n',lsigMCS); % 显示MCS fprintf(' Length: %d\n',lsigLen); % 显示长度 fprintf(' Number of samples in packet: %d\n\n',rxSamples); % 显示包样本数 fprintf(' EVM:\n'); % 显示EVM信息 fprintf(' EVM peak: %0.3f%% EVM RMS: %0.3f%%\n\n', ... evm.Peak,evm.RMS); % 显示峰值和RMS EVM fprintf(' Decoded MAC Sequence Control field contents:\n'); % 显示解码的MAC序列控制字段内容 fprintf(' Sequence number: %d\n\n',packetSeq(pktInd)); % 显示序列号 end % 17. 更新搜索偏移量,准备搜索下一个包 searchOffset = pktOffset+double(indNonHTData(2)); % 将搜索偏移设置为当前包数据字段的末尾之后 % 18. 检查是否检测到重复的数据包 % 如果检测到重复包 (序列号出现重复),则完成处理。 % 恢复的数据将包含重复帧的比特。 % 移除重复帧的数据比特。 if length(unique(packetSeq)) < length(packetSeq) % 如果唯一序列号的数量小于已记录的序列号总数 rxBit = rxBit(1:length(unique(packetSeq))); % 保留不重复部分的数据比特 packetSeq = packetSeq(1:length(unique(packetSeq))); % 保留不重复部分的序列号 break % 退出while循环 end pktInd = pktInd+1; % 增加已处理的数据包计数器 end % 结束 while 循环 (数据包搜索和解码) % 释放SDR硬件资源 (如果使用了空中传输) if strcmpi(channel,"OverTheAir") release(sdrTransmitter); % 释放发射器对象 release(sdrReceiver); % 释放接收器对象 end % 后处理:图像重建和性能评估 if ~(isempty(fineTimingOffset) || isempty(pktOffset)) % 确保至少成功检测并处理了一个包 % 将解码后的比特从单元数组转换为单列向量 rxData = cat(1,rxBit{:}); % 垂直连接所有包的比特数据 % 移除可能多余的比特 (对齐到 msduLength*8 的倍数) % 这步可能不必要,取决于前面填充和提取的逻辑是否精确 % rxData = rxData(1:end-(mod(length(rxData),msduLength*8))); % 重新整形比特数据,使得每列包含一个MSDU的比特 (msduLength*8 比特) numBitsPerMSDU = msduLength * bitsPerOctet; numRxMSDUs = floor(length(rxData) / numBitsPerMSDU); % 计算完整接收的MSDU数量 rxData = rxData(1 : numRxMSDUs * numBitsPerMSDU); % 截断末尾不足一个MSDU的比特 rxData = reshape(rxData, numBitsPerMSDU, numRxMSDUs);% 重塑为矩阵,每列是一个MSDU % 如果存在重复包,则移除它们。重复包位于 rxData 的末尾。 % (注意:之前的逻辑应该在while循环中已经移除了重复包,这里可能是双重保险或处理特殊情况) if length(packetSeq)>numMSDUs numDupPackets = size(rxData,2)-numMSDUs; % 计算多余的包数量 rxData = rxData(:,1:end-numDupPackets); % 只保留预期的 numMSDUs 个包的数据 end % 初始化变量用于寻找起始序列号 startSeqIdx = []; % 起始序列号在 packetSeq 数组中的索引 startSeqNum = -1; % 起始序列号的值 % 只有当至少一个数据包的序列号被正确解码时才执行重排序 if any(packetSeq<numMSDUs) % 检查是否存在有效的序列号 (小于总MSDU数) % 寻找接收到的最小序列号及其索引 [minSeq, minIdx] = min(packetSeq); if minSeq < numMSDUs % 确保找到的最小序号是有效的 startSeqIdx = minIdx; startSeqNum = minSeq; end % 如果找到了有效的起始包 if ~isempty(startSeqIdx) % 对接收到的数据进行循环移位,以便按正确顺序重建图像。 % 假设起始包之后的所有包都按顺序接收 (与发射顺序一致)。 shiftAmount = -(startSeqIdx - 1); % 计算需要左移的位数 (使起始包成为第一列) rxData = circshift(rxData,[0, shiftAmount]); % 对列进行循环移位 fprintf('\nReordered received packets starting from sequence number %d.\n', startSeqNum); else fprintf('\nCould not find a valid starting sequence number. Image might be incorrectly ordered.\n'); end % Reshape rxData matrix back into a single column vector for BER calculation rxDataColVector = rxData(:); % 将重排后的矩阵 rxData 转换回列向量 % Perform bit error rate (BER) calculation on reordered data bitErrorRate = comm.ErrorRate; % 创建误比特率计算对象 % Ensure we compare the same number of bits from Tx and Rx vectors numBitsToCompare = min(length(rxDataColVector), length(txDataBits)); % 确定要比较的比特数 fprintf('Comparing %d bits for BER calculation.\n', numBitsToCompare); % 添加调试信息 % Compare the column vectors err = bitErrorRate(double(rxDataColVector(1:numBitsToCompare)), ... % 接收比特列向量 txDataBits(1:numBitsToCompare)); % 原始发射比特列向量 fprintf(' \nBit Error Rate (BER):\n'); fprintf(' Bit Error Rate (BER) = %0.5f\n',err(1)); fprintf(' Number of bit errors = %d\n',err(2)); fprintf(' Number of compared bits = %d\n\n',err(3)); % err(3) is the number of bits compared else fprintf('\nNo valid packet sequence numbers decoded. Cannot reorder packets or calculate BER reliably.\n'); end % 将重排 (或未重排) 后的比特转换回字节 (整数) decData = bit2int(reshape(rxData(:),bitsPerOctet,[]),bitsPerOctet,false)'; % 每8比特转为一个字节 % 如果接收到的数据少于原始图像数据,则用 NaN 填充缺失部分 if length(decData)<length(txImage) numMissingData = length(txImage)-length(decData); % 计算缺失的数据量 decData = [decData;NaN(numMissingData,1)]; % 用NaN填充 else % 如果接收数据过多 (理论上不应发生,除非原始图像很小或有错误),则截断 decData = decData(1:length(txImage)); end % 从接收到的数据重建图像 fprintf('\nConstructing image from received data.\n'); % 打印信息:正在从接收数据构建图像 % 将数据向量重新塑造成原始 (缩放后) 图像的尺寸,并转换为uint8类型 receivedImage = uint8(reshape(decData,imsize)); % 绘制接收到的图像 if exist('imFig','var') && ishandle(imFig) % 如果发射图像窗口存在且有效 figure(imFig); subplot(212); % 切换到该窗口的第二个子图 else figure; subplot(212); % 否则,创建新窗口并在第二个子图绘制 (如果只有一个子图,则会创建) end imshow(receivedImage); % 显示重建的图像 title(sprintf('Received Image')); % 设置标题: "接收图像" end % 结束图像重建和后处理
最新发布
05-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值