MATLAB超宽带通信系统BPSK调制误码率仿真平台设计与实现 简介本资源是一个面向通信工程专业本科生、研究生及无线通信初学者的MATLAB仿真实践工具聚焦超宽带UWB系统中BPSK调制的误码率性能评估问题。平台通过简洁可复现的代码实现端到端通信链路建模涵盖BPSK调制、加性高斯白噪声AWGN信道传输、相干解调与误码统计全过程并支持不同信噪比下的BER曲线绘制及时频域信号可视化分析为课程设计、课程实验及科研入门提供即开即用的技术支撑。压缩包共2个文件1个核心MATLAB脚本main.m 1份说明文档README.md总大小仅5KB轻量易读便于理解算法逻辑与仿真框架搭建思路。目前已有24人学习下载读者可直接运行main.m获取标准BER-SNR理论曲线与仿真结果对比图结合README中的参数说明与模块注释快速掌握UWB系统下BPSK调制性能分析的关键步骤与MATLAB实现范式。 写通信系统仿真的人应该都有同一种体验拿到一个课题比如“基于MATLAB的超宽带通信系统BPSK调制误码率仿真平台”第一反应是这有什么难的——信号生成、加噪声、统计误码三步就完事。但真把自己关在电脑前做一遍才发现从脉冲成形到能量归一化从采样点对不齐到高信噪比下错误数为零坑一个接一个。这篇就把我做完整个平台的经验完整拆开从系统设计、理论推导到代码实现和避坑实录一次讲清楚做课程设计、毕业设计或者想上手UWB仿真的人都可以直接参考。这个平台做的事不复杂用MATLAB搭建一个完整的超宽带脉冲无线电收发链路发射端随机比特经BPSK映射后通过高斯脉冲成形叠加高斯白噪声接收端采用相关接收完成判决最后统计不同Eb/N0条件下的误码率并把仿真曲线和理论曲线放在一起对比。它的价值在于把抽象通信原理变成了一条能跑、能看、能扩展的仿真链路后续想加多径、加多用户、换脉冲形状都有现成地基。1. 先把整体设计理清楚平台结构与方案选型1.1 为什么这套仿真必须落在MATLAB上很多人在选仿真工具时纠结过Python自由C快MATLAB贵还占内存。但做通信物理层仿真尤其是UWB这种高频脉冲信号MATLAB的向量化运算优势太明显了。一次生成上百万个采样点Python要用NumPy绕来绕去MATLAB直接按矩阵写代码可读性和运行效率都令人满意。还有一个关键点是调试体验。UWB脉冲时间尺度是纳秒级采样率动辄几十GHz数据量大、时序复杂如果每次运行都要重新理解数据结构效率极低。MATLAB的工作区变量可视化、绘图交互、节流调试能让你盯着变量列表逐步核对信号形状是否符合预期。再加上通信工具箱里的理论误码率函数、滤波器函数整个平台开发周期能压缩到两三天。我做这套平台时特意没有依赖额外的通信工具箱函数纯手写脉冲、调制、相关接收和误码统计目的就是让代码在被复制到别的环境时依然能跑原理也更透明。对初学者来说手写一遍比调用封装函数学到的东西多得多。1.2 BPSK在UWB系统里到底强在哪超宽带脉冲无线电的调制方式不算多常见的就这么几种PPM脉冲位置调制、OOK通断键控、PAM脉冲幅度调制、BPSK二进制相移键控。OOK实现最简单非相干接收器只要设置一个能量门限就能判断但性能上有天然劣势PPM对同步精度要求极高要在纳秒尺度上分辨位置变化BPSK的优势在于信息承载在脉冲的极性上符号之间欧氏距离最大在相同信噪比下误码率最低。从理论角度说AWGN信道下BPSK的误码率公式是PeQ(sqrt(2Eb/N0))。这个公式简单、标准、便于验证仿真做出来的曲线是否贴合它直接反映了链路搭建是否正确。正因为它理论清晰我第一次实现时就用BPSK来验证整个平台的数据通路等这条链路完全稳定了再去实现PPM、OOK或者多脉冲调制就只剩下映射函数和判决规则的微小改动。需要注意一个细节BPSK虽然叫“相移键控”但在超宽带场景里我们通常不做高频载波调制而是直接把正负脉冲当作两个符号。这相当于基带BPSK物理上意味着发射端要能生成正反两个极性的脉冲接收端用模板相关即可恢复信息。我后面所有代码都是按这个基带模型写的。1.3 系统模型和性能指标定义整个仿真链路分为五个环节随机比特生成、BPSK符号映射、脉冲成形、AWGN信道叠加、相关接收与判决统计。信道模型先从最理想的高斯白噪声信道开始因为它数学上最干净也最容易校验系统正确性。多径信道、窄带干扰、多用户干扰这些扩展全部是在这个基础骨架上加模块。性能指标用误码率BER和Eb/N0的关系来衡量而不是用简单的信噪比SNR。原因在于Eb/N0把调制阶数和带宽因素归一化了可以公平比较不同系统方案在UWB系统里脉冲宽度直接决定带宽同一个发射功率下脉冲越窄、带宽越大单位比特的能量和噪声谱密度之比就和普通窄带系统不一样只有用Eb/N0才方便和理论值对齐。Eb/N0和SNR的换算关系这里提醒一下Eb/N0 SNR * (B/Rb)其中B是接收机等效噪声带宽Rb是比特速率。很多初学者直接用awgn函数加噪声按经验设一个SNR结果仿真曲线和理论值对不上根源就在这里。我在仿真里改成了自己生成噪声直接控制N0这样Eb/N0的定义不会因为带宽估算误差而跑偏。2. UWB信号模型与误码率理论值推导2.1 超宽带信号的特征和脉冲设计超宽带通信系统之所以叫“超宽带”是因为它的相对带宽或者绝对带宽远超传统窄带系统。按照FCC的定义信号相对带宽大于20%或者-10dB带宽超过500MHz都属于UWB。这种极宽带宽带来了高时间分辨率也带来一个直接后果不能用传统的正弦载波加窄带滤波的方式传输而是直接用极窄的脉冲承载信息所以也叫脉冲无线电。脉冲形状的选择是UWB系统设计里相当关键的一环。理想情况下希望脉冲持续时间尽量短以提高时间分辨率和数据速率但脉冲越窄高频成分越多频谱越宽越容易超出频谱模板限制。实际工程里常用高斯脉冲的各阶导数因为高斯函数时频积最小导数阶数越高频谱重心越往高频移动直流分量越小频谱形状更容易调整。我在代码里选的是高斯脉冲的二阶导公式为[ p(t) \left(1 - 4\pi \left(\frac{t}{\tau}\right)^2 \right) \cdot \exp\left(-2\pi \left(\frac{t}{\tau}\right)^2 \right) ]其中τ是脉冲成形因子控制脉冲宽度。τ越小脉冲越窄、带宽越大。代码里我设脉冲宽度Tp2ns成形因子τ0.5ns采样率取50GHz这样每个脉冲就有100个采样点既保证了波形平滑度又不会让仿真数据量过于庞大。生成脉冲后要做一次能量归一化确保每个脉冲携带的能量等于1焦耳离散域下按采样间隔积分这一步直接关系到后面Eb/N0计算的正确性。2.2 相关接收机结构与最佳判决BPSK信号的接收不能用简单的包络检波因为正负极性并不影响包络大小。正确方式是相关接收把接收信号和本地模板脉冲做内积得到一个判决变量。由于BPSK将比特1映射为p(t)比特0映射为-p(t)判决变量的正负就直接对应发送的比特极性。这个过程的数学本质是匹配滤波。在AWGN信道中匹配滤波是最佳接收准则它能最大化采样时刻的信噪比。离散实现时把接收端的Ns个采样点与镜像后的模板脉冲卷积或在已知帧同步的情况下直接做归一化内积等效。我做平台时选择了后者因为代码更直观也方便逐比特检查。假设发送比特为1接收信号为p(t)n(t)相关器输出为[ V \int r(t)p(t)dt \int p^2(t)dt \int n(t)p(t)dt E_b N_T ][ N_T \sim \mathcal{N}(0, N_0E_b/2) ]所以V服从均值为Eb、方差为N0Eb/2的高斯分布发送比特为0时V的均值变成-Eb。在这两种分布下最佳判决门限是0误码率即单边高斯分布的尾部概率[ P_e Q\left(\sqrt{\frac{2E_b}{N_0}}\right) ]对应到代码里每个比特的相关值如果大于0就判为1小于0判为0统计错误比特数除以总比特数就得到仿真误码率。2.3 蒙特卡洛仿真如何验证理论公式蒙特卡洛仿真就是用随机样本近似统计特性。每运行一次仿真相当于用有限个比特去估计真实的误码率。这个过程存在统计波动理论误差可以估算在95%置信度下误码率的相对误差大约为1.96/sqrt(N*Pe)N是仿真比特数。也就是说如果目标误码率是1e-4想控制相对误差在10%以内至少需要约400万比特。这个数字在实际仿真里不一定总能满足尤其在扫多个信噪比点时计算量会爆炸。我自己的经验是仿真曲线和理论曲线做到趋势一致、偏差在可接受范围内即可不需要在高信噪比区域追求完全重合。比如在Eb/N010dB理论误码率是3.9e-6用20万比特仿真可能一个错误都没有此时计算出来的BER0在对数坐标上就没法画点。这并不代表仿真出错而是样本量不够。如果在论文里需要高信噪比的精确结果可以采用重要性采样或者增加比特数到千万级。平台设计时我留了一个参数入口直接把N_bits从2e5调到2e6代价是仿真时间明显变长但和代码结构无关不用改逻辑。3. 仿真平台实现从发射链路到BER曲线3.1 平台模块划分与整体流程我在搭建平台时把它分成了参数配置、脉冲生成、发射、信道、接收、误码统计、绘图七个独立模块。每个模块用独立的代码段或函数实现方便单独调试。整体流程是先配置参数生成模板脉冲然后进入Eb/N0扫描循环每个信噪比点都重新生成随机比特、完成BPSK映射和脉冲成形、加噪声、相关判决、统计误码扫描结束后计算理论误码率并绘图。模块划分的好处是调试时不用在一大坨代码里找问题。我刚开始写的时候图省事把发射和接收都塞进一个循环里结果曲线不对排查了两天最后发现脉冲模板忘记翻转。拆成模块后每个环节都可以在workspace里拉出波形看一眼输入输出一目了然。这个习惯后来救了我很多次。平台各环节对应的功能和实现方式如下表模块职责实现方式参数配置定义采样率、脉冲宽度、比特数、信噪比范围顶部脚本段常量赋值脉冲生成生成高斯二阶导脉冲并归一化能量手写公式向量化计算发射机随机比特 → BPSK映射 → 脉冲成形randi生成比特kron脉冲扩展信道叠加AWGN按N0计算噪声方差randn生成噪声接收机相关判决、符号判定矩阵列内积阈值0判决误码统计比较判决结果与发送比特sum逻辑比较绘图画仿真与理论BER曲线semilogy双曲线叠加3.2 采样率和脉冲参数的计算参数选取是仿真里最容易出错也最需要理解的一环。我用的参数如下采样率fs50GHz脉冲宽度Tp2ns高斯成形因子tau0.5ns每个脉冲采样点数NsTp*fs100每个Eb/N0点仿真比特数N_bits200000Eb/N0扫描范围0到12dB。采样率为什么定50GHz奈奎斯特定理要求采样率至少是信号最高频率的两倍。高斯二阶导的能量主要集中在低频到约5GHz的范围内50GHz的采样率相当于最高频率的十倍以上波形重建的精度足够。采样率也不是越高越好每提高一倍仿真数据量和运行时间都跟着翻倍所以够用就行。每个脉冲采样点数Ns100意味着发射端每个比特用100个采样点表示。这100个点在接收端作为一个整体做相关运算。Ns选太小波形会失真选太大浪费算力。我试过Ns50也能出结果但脉冲波形看起来有明显阶梯感相关性能会差零点几个dB原因是离散化损失。Ns100算是一个比较舒服的平衡点。脉冲生成和能量归一化的MATLAB代码如下fs 50e9; % 采样率 50GHz Tp 2e-9; % 脉冲宽度 2ns tau 0.5e-9; % 高斯成形因子 Ns round(Tp * fs); % 每个比特采样点数 100 % 高斯二阶导脉冲 t_pulse (-Tp/2 : 1/fs : Tp/2 - 1/fs); pulse (1 - 4*pi*(t_pulse/tau).^2) .* exp(-2*pi*(t_pulse/tau).^2); % 能量归一化使每个脉冲能量为1 pulse_energy sum(pulse.^2) * (1/fs); pulse pulse / sqrt(pulse_energy);注意pulse_energy里的(1/fs)因子。离散序列平方和如果不乘采样间隔数值上等于连续信号的Tp倍后面Eb计算会差一个量级。就这一行当初让我折腾了一整天后面会再展开讲。3.3 发射端BPSK映射与脉冲成形代码发射端逻辑分三步生成随机比特流、把比特映射成符号、用符号调制脉冲序列。随机比特由randi生成0和1等概率映射规则是比特1映射为1比特0映射为-1。这样每个比特在发送波形上的体现就是正脉冲或负脉冲。发射端核心代码如下rng(2024); % 固定随机种子保证结果可复现 bits randi([0 1], 1, N_bits); % 随机比特流 symbols 2 * bits - 1; % BPSK映射1 - 1, 0 - -1 % 脉冲成形每个符号重复Ns次乘上脉冲模板 tx reshape(symbols .* pulse, 1, []);这里用了reshape而不是循环MATLAB的矩阵运算速度远快于for循环。symbols是1×N_bits的行向量pulse是1×Ns的行向量两者做元素乘会产生N_bits×Ns的矩阵再按行展开成一维发射序列。展开顺序正好对应连续脉冲串的时域波形。帧结构上我用的是最简单的单脉冲单比特即每个信息比特占用一个脉冲宽度脉冲之间没有保护间隔。在脉冲宽度为2ns的情况下符号速率是500Mbps这个速率在真实UWB系统里偏高但仿真只是为了验证链路性能物理限制可以暂时不考虑。如果想引入保护间隔只需在reshape时插入零填充改动不大。3.4 信道与接收端噪声添加、相关判决发射信号生成好之后进入信道。我在这里没有用MATLAB自带的awgn函数原因在前面说过awgn按SNR添加噪声需要额外换算带宽和比特速率容易引入误差。更好的做法是自己计算噪声方差。AWGN信道下离散采样点的噪声方差为[ \sigma^2 \frac{N_0 \cdot f_s}{2} ]之所以有fs因子是因为采样后的噪声功率分布在采样带宽内噪声样本方差需要乘上采样率才能等效连续域的功率谱密度。N0则由Eb/N0目标值反推N0 Eb / 10^(EbN0_dB/10)而Eb1脉冲能量已归一化所以N0 10^(-EbN0_dB/10)。接收端相关判决的实现方式很巧妙。把接收序列reshape成Ns行、N_bits列的矩阵第k列正好是第k个比特的Ns个采样值。把这个矩阵和模板脉冲列向量做点乘再按列求和就得到所有比特的相关判决变量。这个操作可以一次性完成完全不需要循环。接收端关键代码如下for idx 1:length(EbN0_dB) EbN0_lin 10^(EbN0_dB(idx)/10); N0 1 / EbN0_lin; % Eb1反推N0 noise_var N0 * fs / 2; % 实基带AWGN方差 noise sqrt(noise_var) * randn(size(tx)); rx tx noise; % 相关接收 rx_mat reshape(rx, Ns, N_bits); decision sum(rx_mat .* pulse(:), 1); % 判决与误码统计 detect_bits double(decision 0); errors sum(detect_bits ~ bits); ber_sim(idx) errors / N_bits; end这里有一个容易忽略的细节pulse(:)把行向量转成列向量这样才能和reshape后的矩阵正确适配维度。如果忘记了冒号转置MATLAB会报维度不匹配或者在某些情况下悄悄用隐式扩展计算出错误结果。我第一次写完这段代码时就因为没有转置结果判决变量的数值全乱了我当时还以为是随机数种子的问题排查了半天才发现是维度没对齐。3.5 主循环、误码统计与绘图前面几段代码组合起来就是完整的仿真主程序。外层循环遍历Eb/N0的每个值内层完成一次完整的蒙特卡洛仿真。理论BER在循环外面一次性算好EbN0_dB 0:1:12; ber_theory qfunc(sqrt(2 * 10.^(EbN0_dB/10))); for idx 1:length(EbN0_dB) % 上述接收端代码 end % 剔除BER0的点避免semilogy取对数出错 valid_idx ber_sim 0; figure; semilogy(EbN0_dB(valid_idx), ber_sim(valid_idx), ro-, ... LineWidth, 1.5, MarkerFaceColor, r); hold on; semilogy(EbN0_dB, ber_theory, b--, LineWidth, 1.2); grid on; xlabel(E_b/N_0 (dB)); ylabel(误码率 BER); legend(仿真结果, 理论曲线, Location, southwest);qfunc是标准正态分布的右尾概率函数和erfc可以互换qfunc(x)0.5*erfc(x/sqrt(2))。两种写法都行看个人习惯。我推荐qfunc代码里语义更直接。循环结构上只有一个for数据量大时可以考虑parfor把不同信噪比点分配到多核并行计算但在单信噪比点内部代码已经是向量化的不需要再手动优化。这里还有一个小技巧高信噪比点可能出现ber_sim为0的情况。semilogy对0取对数会变成负无穷绘图时直接缺一个点不影响其他点输出但曲线看起来会有断裂。代码里我用valid_idx过滤之后曲线在低误码率区域会断开几个点这其实是正常的反而体现了真实仿真结果。3.6 一次实测的结果长什么样我某次运行平台的输出数据如下N_bits取200000噪声种子固定Eb/N0 (dB)仿真BER理论BER07.82e-27.87e-223.71e-23.75e-241.19e-21.25e-262.31e-32.39e-381.65e-41.91e-410020万比特无错误3.87e-60到6dB范围内仿真值和理论值偏差很小8dB时偏差约14%这是蒙特卡洛统计波动的正常表现因为200000比特在理论误码率1.9e-4下只对应约38个错误比特统计噪声占比大。到了10dB理论误码率已经低于4e-6200000比特平均不到1个错误结果为0实在太正常了。实际应用里如果要用这个平台对比不同调制方式的优劣建议把可用的信噪比范围控制在仿真曲线和理论曲线偏差小于20%的区域比如N_bits200000时控制在8dB以内要精确评估更高信噪比的性能就需要成倍增加仿真比特数或用半解析方法。4. 实测中的坑和扩展方向4.1 BER曲线贴不齐理论值先查这五点这个问题是我被问得最多的也是自己踩坑最深的。每次曲线不对先按顺序过一遍下面这五件事大概率能找到问题。第一脉冲能量是否正确归一化。这是最隐蔽也最常见的问题。我记得很清楚第一次把仿真跑通后曲线整体比理论值往右偏了约1.5dB整整调了两天。最后发现脉冲能量计算没有乘采样间隔1/fs导致实际Eb比预设值大与N0的关系就乱了。归一化后的Eb必须等于1这是整个链路数值体系的基础。第二噪声方差公式是否正确。实基带信号加噪要用sigma2 N0fs/2不是直接在N0上乘以什么别的因子。如果用的是复基带模型公式会变成N0fs因为复噪声有实部和虚部两个维度。把实基带当成复基带处理噪声功率会翻倍BER曲线会明显变差。第三BPSK映射和判决方向是否一致。我习惯的映射是1映射为1、0映射为-1判决阈值为0。如果映射反了即1映射为-1判决符号也要相应反转。很多人在这一步用双目时符号搞混导致判决结果整体取反误码率会接近1而不是接近0非常显眼但偶尔会因为随机种子的关系看起来像0.5容易误判成代码逻辑没错。第四采样点对齐。相关接收时reshape的方向必须和发射端一致。MATLAB的reshape默认按列填充发射端生成tx时用的是行展开接收端reshape时要把Ns放第一维否则每一列的数据就不是同一个比特的完整波形相关结果完全错误但代码不会报错这时候曲线会是接近0.5的一条直线。第五随机比特生成和判决比特比较时不要搞混变量名。我在重构代码时有一次把变量名bits改成了tx_bits接收端判决结果detect_bits和它比较一切正常但后来简化代码时不小心把比较对象改成了重新生成的随机序列相当于拿错误比特和错误比特对照曲线确实贴在理论线上但发射端和接收端根本不是同一条数据流。这种错误最坑人因为结果看着完全正常。4.2 高信噪比下曲线断掉、抖动怎么处理高信噪比区域有两个常见现象一是BER变成0导致semilogy画不出点二是抖动明显变大。前者好理解错误比特数为0对数坐标自然没有定义后者则是统计波动导致的信噪比越高同样的样本量覆盖的误码率越低相对误差越大。处理BER0的方案有三种。第一种最简单保持现状让曲线在可显示范围内自然结束同时用文字说明“该信噪比下无错误比特”。第二种是增加仿真比特数比如把N_bits提升到1e6或更高让可显示的BER范围向下延伸。第三种是采用误差统计中的区间估计给出置信上限但这更适合论文级分析日常平台仿真没必要搞这么复杂。抖动问题则要靠提升样本量和固定随机种子来改善。我强烈建议整个平台固定一个随机种子比如rng(2024)这样每次运行结果完全可复现调试时对比不同参数的影响非常方便。如果不固定种子改了某个参数后误码率的小幅变化就分不清是参数影响还是随机波动。对论文撰写还建议在每个Eb/N0点重复跑10到20次取平均误码率。这样可以把随机波动降到很低曲线比理论值还平滑代价是仿真时间成倍增加。时间充足的情况下值得做时间紧张就用固定种子的单次结果配合误差棒说明。4.3 性能优化经验让仿真跑得更快我刚完成第一版平台时跑完整个Eb/N0循环需要将近二十分钟后来优化到一分钟左右。主要做了三件事每一件都值得记下来。第一发射端用向量化而不是循环。最初版本里我用for循环逐个比特生成脉冲串每信噪比点20万比特就要循环20万次。改成reshape和点乘后一次生成整个发射序列速度提升了一个数量级以上。这个优化在Ns较大时尤其明显。第二接收端用矩阵运算而不是循环。把接收信号reshape成矩阵后相关运算变成一次矩阵乘法或点乘求和彻底移除内层循环。这样整个仿真流程只剩一个Eb/N0的外层循环计算效率已经接近MATLAB的极限。第三早期停止策略。在高信噪比点如果已经积累了足够多的错误比特比如超过100个误码率的估计精度已经足够就可以提前结束该点的仿真不用跑满全部比特。实现上是在每统计一定数量的比特后检查错误数达到阈值就跳出。这个优化在高信噪比区域能节约大量时间因为理论误码率越低提前结束的概率越大。但早期停止不适合固定种子复现的场景因为它会让不同信噪比点的实际仿真比特数不一致结果更难以解释。我的做法是保留一个enable_early_stop开关默认关闭跑实验时开启。4.4 从AWGN走向多径信道和RAKE接收AWGN验证通过后整个平台向真实信道扩展是顺理成章的事。室内UWB环境的最大特点是多径信号经过墙壁、家具、人体反射后到达接收端形成密集的时延扩展。IEEE 802.15.4a标准里给出了CM1到CM4几种典型室内信道模型CM1对应直视距环境多径数目少、能量集中CM4对应极度非直视距环境时延扩展大、能量分散。在代码层面接入多径信道并不复杂。最简单的做法是定义一个抽头延迟线信道向量h把发射信号和h做卷积再叠加噪声h [0.8, 0, 0.3, 0, 0.15]; % 多径抽头系数示例 rx_multipath conv(tx, h);但接收端如果用原来的单径模板做相关多径能量并不能都被收集起来性能会明显变差。这就是为什么真实UWB接收机通常使用RAKE接收机——它把不同时延的路径分开处理再把各路径的判决变量按最大比合并。在仿真里实现一个两径或三径的RAKE接收机代码量不大但对理解多径分集非常有效。我做过一个简单实验同样的BPSK发射信号在双径信道下用单径相关接收BER曲线在高信噪比区域出现明显平台换成两径RAKE后平台消失曲线接近单径AWGN的理论值。这个实验放到平台上十分钟就能跑完比枯燥地读公式直观得多。后续如果想往更深的科研方向走还可以在此基础上加脉冲重复编码、跳时多址、窄带干扰抑制这些模块平台骨架都够用。最后再分享一个我在这个项目上反复踩过的坑。做仿真最怕的不是代码报错而是代码不报错但结果是错的。第一次整套代码跑通看到仿真曲线和理论曲线完美贴合我以为大功告成。后来改了脉冲宽度参数曲线立刻偏移了才意识到之前只是参数碰巧对上了。从那以后我每次改参数都会先检查脉冲能量归一化再跑一遍理论曲线的对比确认偏差在合理范围内才继续。这个习惯让我在后续的仿真项目里少走了很多弯路也希望读这篇的人能从第一步就养成它。本文还有配套的精品资源点击获取