第 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.');

✅逻辑说明

  1. M=16,每个符号携带k=log2​(16)=4比特。
  2. Nsym=10:一共 10 个调制符号;总比特数10×4=40。
  3. bits:列向量,40×1,原始串行比特流。
  4. 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
    
  5. 还原串行比特:reshape(b.',[],1),先转置回到 4×10,再拉伸为列向量,恢复原始串行比特。
  6. 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 报错并解释原因。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐