ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Simulink AD/DA转换器仿真:采样量化与串并转换链路实践

Simulink AD/DA转换器仿真:采样量化与串并转换链路实践 简介这份资源是一份面向通信工程、电子信息工程等专业学生的课程设计报告围绕A/D与D/A转换器的仿真展开采用Matlab/Simulink作为建模与验证环境适合正在做通信原理课程设计、需要参考完整报告框架与仿真建模思路的读者。资源包内共1个docx文档约78KB内容为通信原理课程设计报告正文涵盖设计目的与要求、开发环境介绍、A/D采样量化编码与D/A恢复滤波的原理说明以及Constant、Zero-Order Hold、Quantizer、Integer to Bit Converter、Buffer、Bit to Integer Converter等模块的功能与参数设置。报告还给出仿真电路原理图、量化与并串转换的仿真结果分析例如输入17.5经量化间隔1处理后输出18的过程并附有设计总结与心得体会。目前已有338人学习下载可作为课程设计报告的写作范本与Simulink建模的入门参照帮助读者快速理清A/D、D/A转换的设计流程、模块选型与参数调试要点。1. 从一次课程设计说起AD 和 DA 转换器仿真到底在验证什么课程设计里最容易被糊弄过去的一步恰恰是 A/D 和 D/A 转换器的仿真。Constant 里输一个 17.5量化器输出 18编码成 8 位比特流串行发出收端再并回来——链路上任何一个参数错位示波器波形立刻给你难看的脸色。这类 AD 和 DA 转换器仿真真正的价值是把采样定理、量化误差、串并转换这三块通信原理里的硬骨头塞进一个能反复改参数、反复看结果的模型里。适合谁正在做通信原理课程设计、要交一份跑得通的 Simulink 报告的同学关心模块怎么连、参数怎么填也想用 Simulink 快速搭一条数据采集与回放链路、验证算法边界的工程师更关心采样时间与量化位宽怎么取舍、Buffer 长度怎么定、仿真数据怎么导出到工作空间算误差。2. 采样定理、量化间隔与比特映射建模前的数学模型动手拖模块之前先把三件事算清楚采样率取多少、量化间隔取多少、比特序怎么定。这三件事在 Simulink 里分别落到 Zero-Order Hold 的 Sample time、Quantizer 的 Quantization interval、Integer to Bit Converter 的 Output bit order 三个参数上填错了不会报错只会给你一组看似合理但完全错误的波形。2.1 零阶保持器为什么能当采样保持电路理想采样的数学模型是冲激串乘以模拟信号频谱上表现为周期延拓。Simulink 里没有理想冲激采样模块最接近的是 Zero-Order Hold在每个采样时刻读取输入值然后保持到这个采样周期结束输出是阶梯波也就是教科书里的平顶抽样。ZOH 的冲激响应是一个宽度为 T 的矩形对应的频率响应是 sinc 函数在 1/T 的整数倍频率处有零点。这意味着平顶抽样相对理想冲激采样多了一个 sinc 包络的幅度衰减高频分量被轻微压低。在课程设计这种量级下这个包络不影响结论但要心里有数如果后面做的是宽带信号重构这个衰减就得用补偿滤波器拉回来。采样率的选择还是要回到采样定理fs ≥ 2·fmax。Zero-Order Hold 的 Sample time 填 1s等价于采样率 1Hz理论上能无失真还原的最高信号频率是 0.5Hz。这个数字看着很慢但配合 Integer to Bit Converter 每整数 8 比特的输出仿真的信息量和耗时都控制在可接受的范围内。提示Constant 模块输出的是常数经过 ZOH 之后波形仍然是直线看不出任何阶梯。很多人因此以为采样模块没工作。想看采样效果把 Constant 换成 Sine Wave频率取 0.2Hz 左右再把仿真时间拉长到 20s 以上。2.2 Quantizer 的量化间隔与量化信噪比Quantizer 模块做的事很简单把输入值舍入到最近的、量化间隔的整数倍。Quantization interval 填 1Sample time 填 -1前者决定量化台阶的大小后者表示采样时间继承上游模块不要在这里另设一个采样率。对输入 17.5、量化间隔 1 的情况17.5 / 1 17.5舍入到最近的整数是 18量化误差 0.5刚好等于 q/2是均匀量化器能产生的最大误差。这个结果和底层浮点舍入规则一致MATLAB 的 round 对 .5 采用远离零方向舍入两边对齐所以仿真不会出现 17 和 18 打架的情况。均匀量化器的误差在 [-q/2, q/2] 内近似均匀分布噪声功率是 q²/12。满量程正弦输入下量化信噪比有个好记的近似式SQNR ≈ 6.02n 1.76 dBn 是量化位宽。每加一位信噪比提升约 6dB。下面这张表能帮你快速判断位宽和量化间隔该取多少量化位宽 n量化级数 2ⁿ满量程 SQNR 近似值覆盖 0~255 时的量化间隔41625.8 dB16825649.9 dB112409674.0 dB1/16166553698.1 dB1/256本设计里 Constant 的取值范围是 0~2558 位刚好能无溢出地覆盖这 256 个电平量化间隔取 1 时既不浪费量化级数也不产生截断。位宽换成 7 位255 就会溢出换成 12 位则有一半以上的编码空间永远用不到。2.3 整数与比特流的双向映射A/D 的最后一步是编码。Integer to Bit Converter 把 0~2^M-1 的整数转成 M 位二进制M 由 Number of bits per integer 决定本设计取 8。Treat input values as 选 Unsigned因为输入不会有负数一旦选成 Signed17.5 对应的整数会被当成补码解释收端还原出来就是另一回事。Output bit order 选 MSB first意思是最高有效位排在输出向量的第一个位置。8 位无符号整数 18 的二进制是 00010010MSB first 输出的向量就是 [0 0 0 1 0 0 1 0]拆开写是 0、0、0、1、0、0、1、0。收端的 Bit to Integer Converter 必须同样选 MSB first否则得到的是位序反转的结果01001000也就是 72。先把数学模型用几行脚本验证一遍比在 Simulink 里盲调参数快得多q 1; % 量化间隔对应 Quantizer 的 Quantization interval nbits 8; % 量化位宽对应 bits per integer x 17.5; % 待量化的模拟采样值 y q * round(x / q); % 四舍五入到 q 的整数倍与 Quantizer 行为一致 code dec2bin(y, nbits); % 转成 nbits 位二进制串MSB 在最左 sqnr 6.02 * nbits 1.76; % 满量程正弦输入下的理论量化信噪比 fprintf(量化输出 y %d\n, y); fprintf(二进制码 code %s\n, code); fprintf(理论 SQNR %.1f dB\n, sqnr);这段脚本里round承担的是 Quantizer 的角色dec2bin承担 Integer to Bit Converter 的角色sqnr那一行只是拿来对照不参与转换。跑出来 y18、code00010010、SQNR≈49.9dB这三个数就是后面判断 Simulink 波形对不对的基准。3. 从 Constant 到 Bit to Integer一条完整链路的搭法模型分三段前向的采样与量化、中间的编码与串行化、收端的还原与反量化。段与段之间靠数据类型和维度衔接维度对不上是这类模型最常见的报错来源。3.1 前向通道Constant、Zero-Order Hold、QuantizerConstant 的 Constant value 填 17.5Sample time 填 1让信号源本身也是离散的避免模型里混入连续采样点。Zero-Order Hold 的 Sample time 同样填 1。Quantizer 的 Quantization interval 填 1Sample time 填 -1继承上游速率。这三个模块串起来之后链路上传递的还是一个标量序列只是数值已经被约束到整数格点上。想验证采样保持确实起作用把 Constant 换成 Signal Generator波形选锯齿波频率 0.2Hz示波器上看前两级ZOH 之前是斜线之后是台阶。3.2 编码与并串转换Integer to Bit Converter 到 BufferInteger to Bit Converter 输出的是长度 8 的向量但它默认按采样点逐个处理一个采样点对应一个向量。Frame Status Conversion 的作用是把这 8 个并行比特声明成一帧Sampling mode of output signal 选 Frame-based。这一步是很多人的盲区不做帧声明下游 Buffer 会按样本维度去缓冲缓冲出来的东西根本不是你要的比特流。Buffer 模块负责把帧内的比特按顺序推出去。报告里对模块 6 的描述是「串行化输出Buffer 大小设置为 1」但参数记录写的是 Output buffer size 8这两处是矛盾的。按串行化的语义Output buffer size 应该填 1表示每个采样时刻输出一个比特Buffer overlap 填 0Initial conditions 填 0。注意如果按记录里的 8 去填Buffer 输出的仍然是一个 8 元素的并行帧并没有串行化。收端 Buffer1 再设成 8两级缓冲叠加维度就会报错。这个坑在交报告前一定要自己跑一遍确认别照抄参数表。3.3 收端还原Buffer1、Reshape 与 Bit to Integer Converter收端第一步是把串行比特流重新攒成 8 位一组。Buffer1 的 Output buffer size 填 8Buffer overlap 填 0Initial conditions 填 0输出是一个帧格式的 8 元素向量。这个向量要送进 Bit to Integer Converter但后者期待的是数组格式而非帧格式中间得插一个 ReshapeOutput dimensionality 选 1-D array。Bit to Integer Converter 的参数与编码端严格对称Number of bits per integer 填 8Input bit order 选 MSB firstAfter bit packing, treat resulting integer values as 选 UnsignedOutput data type 选 Inherit via internal rule。三处任一处与编码端不一致还原出来的整数都是错的。模块关键参数取值作用ConstantConstant value / Sample time17.5 / 1模拟直流输入源Zero-Order HoldSample time1采样保持平顶抽样QuantizerQuantization interval / Sample time1 / -1幅度离散化Integer to Bit ConverterNumber of bits per integer / Treat input as / Output bit order8 / Unsigned / MSB first整数转并行比特Frame Status ConversionSampling mode of output signalFrame-based声明并行比特为一帧BufferOutput buffer size / Buffer overlap1 / 0帧转串行比特流Buffer1Output buffer size / Buffer overlap8 / 0串行比特流攒回并行帧ReshapeOutput dimensionality1-D array帧格式转数组格式Bit to Integer ConverterNumber of bits per integer / Input bit order8 / MSB first并行比特还原整数3.4 用脚本重建模型避免重复拖拽模块多了以后手工拖拽容易漏连、错连改一版参数要重来一遍。可用 add_block 和 add_line 把建模过程写成脚本。不同 MATLAB 版本里通信模块的库路径会变先按名字把路径搜出来再建模块% 库路径随版本变化先按名字搜索拿到路径再 add_block libs {simulink, simulink_extras, commlib, dsplib}; names {Integer to Bit Converter, Frame Status Conversion, Reshape, Buffer}; for i 1:numel(libs) for j 1:numel(names) p find_system(libs{i}, SearchDepth, 4, Name, names{j}); if ~isempty(p) fprintf(%-28s - %s\n, names{j}, p{1}); end end end拿到路径后用 add_block 逐个实例化参数通过名称-值对直接写死比双击对话框填参数更不容易出错model ad_da_demo; if bdIsLoaded(model), close_system(model, 0); end new_system(model); open_system(model); % 前向通道信号源 - 采样保持 - 量化 add_block(simulink/Sources/Constant, [model /Const], ... Value, 17.5, SampleTime, 1, Position, [30 100 70 130]); add_block(simulink/Discrete/Zero-Order Hold, [model /ZOH], ... SampleTime, 1, Position, [110 100 150 130]); add_block(simulink/Discrete/Quantizer, [model /Quant], ... QuantizationInterval, 1, SampleTime, -1, ... Position, [190 100 230 130]); % 串联discrete 模块的端口顺序是 1 进 1 出 add_line(model, Const/1, ZOH/1, autorouting, on); add_line(model, ZOH/1, Quant/1, autorouting, on); set_param(model, StopTime, 20, ... Solver, FixedStepDiscrete, FixedStep, 1);求解器必须选 FixedStepDiscrete固定步长设为 1与 ZOH 的采样周期一致。用变步长连续求解器去跑一个纯离散模型会出现步长自动细分、离散模块在非采样点上被反复调用的问题仿真变慢波形也可能出现莫名其妙的抖动。4. 参数怎么定采样时间、Buffer 长度与帧格式的耦合三个参数不是独立的采样时间决定数据产生的节拍量化间隔决定数值的粒度Buffer 长度决定并串转换的切分点。改一个另外两个的合理性都要重新评估。4.1 采样时间与量化间隔是两回事Sample time 管的是时间轴上的离散化Quantization interval 管的是幅度轴上的离散化两者都叫「离散」但作用维度完全不同。整条链路除 Zero-Order Hold 之外其余离散模块的 Sample time 都建议填 -1让 Simulink 自动继承上游速率模型里只有 ZOH 一个速率源。如果手贱把 Quantizer 的 Sample time 也写成固定值比如 0.5同时 ZOH 还是 1Simulink 会插入 rate transition 模块做速率匹配缓冲分组随之错位Buffer 一次攒的 8 个比特可能跨越两个采样点。这类问题不会报错只会让收端还原出的整数缓慢漂移排查起来很费时间。4.2 Buffer 的 size 与 overlap 怎么配Buffer 模块的两个参数是一对Output buffer size 决定每次输出多少个样本Buffer overlap 决定相邻两帧之间重叠多少样本。overlap 必须小于 size否则模型直接报错。串行化场景下发送端用 size1、overlap0接收端用 size8、overlap0。Output buffer sizeBuffer overlap输出行为适用位置10每个采样时刻推 1 个样本等效串行发送端帧转串行80每 8 个样本凑成一帧整体输出接收端串行转帧84相邻帧重叠 4 个样本输出量翻倍滑窗类处理本设计不用88非法overlap 不得大于等于 size会直接报错overlap 不为 0 时同一批比特会被重复送出收端还原出来的整数序列会出现额外样本误以为是量化器出了问题。课程设计追求的是清晰的对应关系overlap 一律取 0。4.3 帧格式与 Reshape维度对不上的典型报错Buffer1 输出的是帧格式Bit to Integer Converter 期待数组格式中间的 Reshape 就是用来消解这个差异的。Reshape 的 Output dimensionality 选 1-D array维度不写死时用 -1 让 Simulink 自动推断写死成 [8] 也可以前提是上游帧宽确实是 8。想知道每一级端口上真正的维度不要让仿真跑完再猜先更新模型再读端口属性set_param(model, SimulationCommand, update); % 只做编辑期更新不跑仿真 blk [model /Buffer1]; ph get_param(blk, PortHandles); dims get_param(ph.Outport(1), CompiledPortDimensions); disp(dims); % 形如 [2 8]第一位是维度数第二位是帧宽返回值的第一个元素是维度个数第二个才是每一维的长度。看到 [2 8] 说明这一级输出的是长度 8 的向量和 Bit to Integer Converter 的 nbits8 匹配看到 [2 1] 说明前面某个 Buffer 的 size 被写成了 1比特没有攒成组收端自然还原不出整数。4.4 一条可复现的验证路径每次改完参数按 17.5 → 18 → 00010010 → 18 这条链手工核对一遍比盯着示波器看波形高效x 17.5; q 1; nbits 8; y q * round(x / q); % 量化17.5 - 18 b dec2bin(y, nbits); % 编码00010010 bits double(b - 0); % 转成数值向量模拟 Integer to Bit Converter 输出 bits flip(bits); % 故意反转位序模拟收端选错 bit order z polyval(bits, 2); % 按二进制权值求和 - 72 fprintf(%g - %d - %s - 误还原 %d\n, x, y, b, z);polyval(bits, 2)这一行把比特向量当成二进制系数求和等价于 bin2dec但不需要再转字符串方便在脚本里批量处理。跑出来是 72 而不是 18就说明位序错位的代价有多大。把flip那一行去掉再跑一次得到 18两端参数就对齐了。5. 导出仿真数据做误差统计以及波形异常的排查顺序看示波器能判断波形形状对不对但判断不了量化误差的分布、有效位数这些量化指标。把数据捞到工作空间里算才算是真的把仿真用起来了。5.1 To Workspace 与量化误差后处理在收端信号后面接一个 To Workspace 模块Save format 选 Structure with timeVariable name 填 doutLimit data points to last 取消勾选。仿真结束后在工作空间里直接做统计t dout.time; % 时间向量 y squeeze(dout.signals.values); % 还原序列去掉多余维度 q 1; % 与 Quantizer 的量化间隔保持一致 xq q * round(y / q); % 反量化参考值 err y - xq; % 量化误差 fprintf(最大误差 %.3f均方根误差 %.4f\n, max(abs(err)), rms(err)); fprintf(实际量化台阶数 %d\n, numel(unique(xq)));squeeze用来消掉 To Workspace 保存时多出来的单维度不写这一句后面做减法会因为维度不一致报错。理论上最大误差不会超过 q/2 0.5均方根误差应在 q/√12 ≈ 0.289 附近。如果实测的最大误差明显超过 0.5说明链路上还有别的模块在动数值比如收端的 Reshape 丢样本或者 Buffer overlap 不为 0 导致重复计数。有了均方根误差还能反推有效位数ENOB (SINAD − 1.76) / 6.02。满量程正弦输入下8 位理想的 ENOB 接近 8实测掉到 6 以下就要回头查量化间隔是不是被改过、编码位宽是不是和量化级数不匹配。5.2 波形异常的排查顺序症状可能原因定位手段波形始终是直线信号源是常数采样保持看不出变化换成 0.2Hz 正弦或锯齿波台阶宽度远大于 1s求解器步长与 ZOH 采样周期不一致求解器改 FixedStepDiscrete步长设 1收端整数缓慢漂移链路上出现多速率rate transition 打乱分组除 ZOH 外Sample time 一律填 -1还原值是原值的位反转结果两端 bit order 不一致统一选 MSB first报维度不匹配Buffer overlap 大于等于 size或 Reshape 维度写错用 CompiledPortDimensions 逐级打印帧宽负数或超大整数编码端误选 SignedTreat input values as 改回 Unsigned最后补一个容易被忽略的细节仿真时间不要一上来就设几百秒。整条链路是纯离散的固定步长 1s跑到 20s 只有 20 个采样点足够看清 17.5 到 18 的量化结果和 8 位比特流的并串转换过程。想观察量化误差随输入变化的规律用 MATLAB 脚本扫一遍 0 到 255 的整数输入比在 Simulink 里改一百次 Constant 快得多——毕竟量化器做的事只有一件把输入舍入到最近的量化格点上。本文还有配套的精品资源点击获取
返回列表