手把手实战 MATLAB 通信系统仿真 02
第 2 章 MATLAB 数组、复数与向量化
|
本章目标 掌握通信仿真中最常见的向量、矩阵、逻辑索引和复数操作;理解 .*、*、./、/ 的区别;能写出不依赖 for 循环的星座映射代码。 |
2.1 为什么通信仿真特别依赖向量化
一次 BER 仿真常常需要处理 10^5~10^7 个比特。若每一个比特都用 for 循环逐个处理,代码不仅慢,而且更容易出现索引错误。MATLAB 最擅长的是整块数组运算。例如 BPSK 映射只需要 tx = 2*bits - 1,而不是写一个循环判断每个元素。
|
写法 |
含义 |
通信中的例子 |
|
a.*b |
逐元素相乘 |
信号乘载波、信道系数 h.*x |
|
A*B |
矩阵乘法 |
MIMO:y = H*x |
|
a./b |
逐元素相除 |
一拍均衡:y./h |
|
A\b |
解线性方程 |
ZF 检测:xHat = H\y |
|
abs(z) |
复数幅度 |
包络、星座半径 |
|
angle(z) |
复数相位 |
载波相位、频偏估计 |
|
conj(z) |
复共轭 |
相关器、匹配滤波 |
2.2 复基带:I/Q 是通信 MATLAB 的核心语言
一个复数 z = I + jQ 同时携带两个正交维度。MATLAB 用 real(z) 取 I 路,用 imag(z) 取 Q 路,用 abs(z) 得幅度,用 angle(z) 得相位。QPSK、QAM、OFDM、MIMO 基本都在复基带域工作。
代码|复数与欧拉公式的 MATLAB 验证【基础 MATLAB】
theta = linspace(-pi,pi,1000);
z = exp(1j*theta);
maxErrI = max(abs(real(z) - cos(theta)));
maxErrQ = max(abs(imag(z) - sin(theta)));
fprintf('I支路最大误差 = %.3e\n',maxErrI);fprintf('Q支路最大误差 = %.3e\n',maxErrQ);
figure('Color','w');subplot(1,2,1);plot(real(z),imag(z),'LineWidth',1.2);
axis equal; grid on;xlabel('Inphase I'); ylabel('Quadrature Q');title('e^{j\theta} 复平面(单位圆)');
subplot(1,2,2);plot(theta, real(z), 'b-', theta, imag(z),'r--','LineWidth',1.2);
grid on;xlabel('\theta (rad)');legend('I=cos(\theta)','Q=sin(\theta)','Location','best');title('I/Q分量随相位变化');
运行后应观察:误差应接近机器精度;图像应为单位圆。
2.3 reshape 是高阶调制的必修函数
16QAM 每个符号携带 4 bit,因此最常见操作是把一条比特流每 4 个分成一组。注意 MATLAB 按列存储,所以 reshape 的方向必须明确。
代码|把比特流分组为每符号 k bit
M = 16;
k = log2(M);
Nsym = 10;
bits = randi([0 1],Nsym*k,1);
% 每一行对应一个符号的 k 个比特
b = reshape(bits,k,[]).';
% 把每行比特转为符号索引,两种位序对比
symIdx_lsb = bi2de(b); % 默认,右为LSB
symIdx_msb = bi2de(b,'left-msb'); % 左为MSB
% 恢复成原始比特流
bitsBack = reshape(b.',[],1);
assert(isequal(bits,bitsBack));
disp('原始串行比特前20位:');
disp(bits(1:20).');
disp('b矩阵(每行1符号的4bit):');
disp(b);
disp('符号索引(默认LSB):');
disp(symIdx_lsb.');
disp('符号索引(left‑msb):');
disp(symIdx_msb.');
✅逻辑说明
M=16,每个符号携带k=log2(16)=4比特。Nsym=10:一共 10 个调制符号;总比特数10×4=40。bits:列向量,40×1,原始串行比特流。reshape(bits,k,[]).'reshape(bits,4,[])→ 4 行 ×10 列:每一列是一个符号的 4 个比特;- 转置
.'→b变成10 行 ×4 列;每行 = 1 个符号对应的 k 比特,这是通信仿真非常经典的比特矩阵格式。
b(1,:) → 第1符号的4bit b(2,:) → 第2符号的4bit ... b(10,:) →第10符号的4bit- 还原串行比特:
reshape(b.',[],1),先转置回到 4×10,再拉伸为列向量,恢复原始串行比特。 assert(isequal(bits,bitsBack)):如果前后比特完全一致,无输出;不一致直接报错终止,用来校验 reshape 操作没有破坏比特。
注意:
reshape只改变矩阵维度,不修改内存中数据顺序,所以正反 reshape 可以无损还原。
⚠️两个容易踩的坑(写 CSDN 可以重点写)
坑 1:.'与'的区别
b.':非共轭转置,只交换行列,比特不变(本代码正确写法)b':共轭转置;实数比特 0/1 看不出差别;如果矩阵是复数,会取共轭,直接破坏数据!
通信仿真强烈习惯用
.',不要简写'。
坑 2:比特排布顺序(MSB/LSB)
现在只是把比特分组,没有规定每行内部比特哪个是高位、哪个是低位。 后面做 16‑QAM 映射的时候,要明确:
matlab
% 示例:把b的每行4比特转成十进制整数
symIdx = bi2de(b); % 默认:每行最右边是LSB最低位
symIdx = bi2de(b,'left-msb'); % 每行最左边是MSB最高位
很多人仿真 BER 对不上理论,就是bi2de 比特位序搞反,reshape 本身没问题,但是 bi2de 调用参数错。
运行后应观察:assert 不报错,说明分组与恢复完全一致。
|
调试技巧 看到维度不匹配错误时,不要先乱加转置符号。先执行 size(A)、size(B),写在纸上,再决定是矩阵乘还是逐元素乘。 |
本章小结
• 复数是 I/Q 表示的自然工具。
• reshape、逻辑索引、逐元素运算是高效通信仿真的基本功。
• A\b 与 A./b 完全不同:前者解线性系统,后者逐元素除法。
动手练习
1. 生成 1000 个 QPSK 星座点,并分别画 real、imag 的直方图。
2. 构造一个 2×2 复矩阵 H 和 2×1 向量 x,计算 y=H*x,再用 H\y 恢复 x。
3. 故意把 .* 改成 *,记录 MATLAB 报错并解释原因。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)