全息MIMO表面这个方向,是我在跑多用户通信仿真时偶然踩进去的。一开始只是被“全息”这个词吸引,以为是某种光学上的全息投影,后来才搞清楚,它是天线阵列和超表面理论结合出来的一种高密度辐射结构。等我用Matlab把多用户场景下的信道模型搭起来、算完频谱效率之后,才意识到这个技术对于频谱资源利用率的提升有多直接。这篇东西就想把整套仿真链路讲清楚:从全息MIMO表面的工作原理,到信道建模的数学构造,再到Matlab代码如何一步步落地,以及频谱效率分析里那些容易踩的坑。
这篇内容适合三类人:一是正在做MIMO/大规模天线方向课题的研究生,二是想快速上手全息MIMO表面仿真验证的工程师,三是对智能超表面、波束赋形感兴趣的通信爱好者。不需要你提前了解太深的天线理论,但最好用过Matlab,知道矩阵运算是怎么回事。我会带着你把信道模型拆开揉碎,再拼回去。
1. 为什么叫“全息”表面:它和传统MIMO阵列的本质区别
1.1 传统MIMO靠离散天线,全息表面靠连续辐射口径
我们先来想想传统MIMO天线阵列是什么样:一排看得见、数得清的天线单元,每个单元独立射频链路,单元间距通常取半波长左右。到了大规模MIMO系统里,64根、128根天线已经很常见,但再往上增加,硬件成本和功耗会爆炸式增长。
全息MIMO表面(Holographic MIMO Surface)的思路完全不同。它更像一个连续的电磁辐射口径,可以理解成把整个平面划分成了成百上千个亚波长尺寸的“像素化”单元,每个单元都能调控反射或辐射电磁波的幅度和相位。天线数量不再受物理射频链路限制——理论上,一个表面上可以布置上万个子单元,但实际需要的射频链路数可能只有几十个。
我最初接触这个技术的代码工程时,脑子里冒出的一个类比是:普通MIMO像一排独立开关的灯,开几盏灯就是几个通道;全息MIMO表面则像一块LED屏幕,每个像素点都能局部变色,但控制它们的驱动芯片可以复用。这里所谓的“全息”,并不是真的记录了光波的干涉条纹,而是借用了全息图那种同时控制幅度和相位、让波前“按需成形”的思想。
1.2 从信道角度看全息表面带来的自由度变化
在多用户MIMO系统中,频谱效率的提升本质上是空间自由度的利用。传统MIMO的最大空间自由度受限于收发端天线数量的较小值。但全息MIMO表面由于单元数密集、口径连续,它能更精细地塑造波束,对标称上“多用户隔离”提供额外的调控维度。
具体到Matlab仿真,你不会把上万个单元逐一建模,而是要把表面等效成一个具有特定响应函数的连续口径模型,再通过采样或波束空间分解来得到信道矩阵。这样做既保证了仿真速度,也能抓住全息表面的主要信道特征。
我做的仿真里,全息MIMO表面放在基站侧,每个用户还是普通的单天线或双天线设备。基站侧表面单元数设为128(这个数对建模已经很够用),射频链路数设为32。这样既能体现全息表面从大量自由单元合成波束的优势,又不会让信道矩阵大到跑不动蒙特卡洛仿真。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 多用户全息MIMO信道建模:从物理传播环境到Matlab可执行代码
2.1 信道矩阵的数学结构:直达径、反射径和路径损耗
信道建模是整个频谱效率分析的地基。在全息MIMO表面场景下,我采用了一个折中方案:把每个用户到基站的无线信道建模为空间相关信道,包含一个主要直达径分量和若干条散射径分量。
对于一个均匀平面阵列(UPA)形状的全息表面,簇到达角(Azimuth AoA)和俯仰角(Elevation AoA)会影响阵列响应向量。用户到基站的复信道向量可以写为:
h = sqrt(beta) * [ sqrt(kappa/(1+kappa)) * a(theta_AoA, phi_AoA) + sqrt(1/(1+kappa)) * (1/sqrt(N_clust)) * sum_{c=1}^{N_clust} alpha_c * a(theta_c, phi_c) ]
其中beta是大尺度衰落系数,kappa是莱斯因子,a(...)是阵列导向向量,alpha_c是散射簇的复增益。这个公式看起来复杂,但拆开看并不难:前面那项是主路径,后面那一堆是围绕主路径的弥散分量。
Matlab实现时,我会让莱斯因子随用户是否为视距状态而变化。对于多用户场景,一般把室内用户设成高莱斯因子,把室外或者遮挡严重的用户设成低莱斯因子。这样模拟出来的信道更贴近实际。
2.2 阵列导向向量的核心写法
全息MIMO表面虽然不是普通天线阵列,但在仿真时我还是把它当成一个UPA来处理,只不过单元间距可以设得比传统ULA(均匀线性阵列)更小。假设表面位于xz平面,x方向有N_x个单元,z方向有N_z个单元,那么任意方向(theta, phi)的导向向量可以表示为外积形式:
a_theta_phi = kron( a_x, a_z )
其中a_x是x方向ULA阵列响应,a_z是z方向ULA阵列响应。角度定义需要和具体坐标系统一,否则很容易出现波束指向错误。
在Matlab中,我会用一个子函数生成这个导向向量:
matlab复制function a = upa_array_response(Nx, Nz, dx, dz, theta, phi)
% theta: 俯仰角(0为视轴方向,通常用-90到90)
% phi: 水平方位角
k = 2*pi; % 波长归一化
x_idx = (0:Nx-1) - (Nx-1)/2;
z_idx = (0:Nz-1) - (Nz-1)/2;
ax = exp(-1j * k * dx * x_idx.' * sin(theta) * cos(phi));
az = exp(1j * k * dz * z_idx.' * cos(theta));
a = kron(ax, az);
end
这里有几个细节容易坑人:一是sin和cos的配位,二是符号方向,三是索引归一化。如果你的阵列响应做反了,后面算出来的频谱效率会低得离谱,而且你根本看不出是哪一步错了。我的经验是拿到这个子函数后先做一个波束方向扫描图,检查峰值是否出现在预设角度,再做后续运算。
2.3 空间相关性和多用户信道的生成
有了单用户信道向量生成函数,多用户场景需要保证不同用户之间的空间分布是随机的、且具有独立的大尺度衰落。我会采用一个循环来生成所有用户的信道:
matlab复制H = zeros(N_rf, N_users); % 若基站侧先做模拟波束赋形降维
for u = 1:N_users
position_u = [rand*range_x, rand*range_z]; % 用户坐标
[theta_u, phi_u, dist_u] = compute_angle_from_position(position_u, bs_pos);
beta_u = pathloss(dist_u, pathloss_exp);
H(:,u) = generate_channel(Nx, Nz, beta_u, kappa_u, theta_u, phi_u);
end
N_rf不是总的单元数,而是射频链路数。这里的等效信道矩阵是经过一个降维矩阵F_rf之后得到的。在全息MIMO表面工程中,不可能给每一个单元都接一套ADC/DAC,所以需要先从大量单元合成若干波束,再用这些波束去服务用户。
我用一个随机化的DFT码本矩阵来模拟这种波束选择。更靠近硬件的做法是用正交匹配追踪去选择波束子集,但为了先验证频谱效率趋势,DFT码本已经够用。
2.4 一个关键点:用户数量和单元数量不匹配时怎么办
很多初学者一上来就让用户数等于总的阵列单元数,结果发现系统容量上不去。原因很简单:信道矩阵的有效秩受限于射频链路数,而不是表面单元数。全息MIMO表面之所以“特别”,不是因为它能同时服务几百个用户,而是它在给定射频链路数下,能提供更高的波束成形增益和更好的用户隔离。
在仿真中,我通常保持用户数K小于等于射频链路数N_rf。如果你想模拟几十个用户,那射频链路起码要大于等于这些用户的满秩空间流需求。否则后续做ZF预编码时伪逆会不稳定,频谱效率曲线出现莫名其妙的凹陷。
3. 频谱效率计算:不是简单套香农公式,还要看预编码和功率分配
3.1 把多用户信道变成多个并行数据流
频谱效率分析最终落地是每一用户可达速率的求和。对于一个有K个用户的MU-MIMO下行链路,如果基站使用迫零预编码,那么每个用户的信干噪比可以简化成:
SINR_k = (P_t/K) * |h_k^H w_k|^2 / (sigma^2 + (P_t/K) * sum_{j != k} |h_k^H w_j|^2)
迫零预编码的权值矩阵W取信道矩阵H的伪逆。在Matlab里就是:
matlab复制W = H / (H' * H); % 相当于 H * inv(H'*H)
W_norm = W ./ vecnorm(W, 2, 1); % 列归一化,保障功率约束
注意矩阵维度和方向。这里H是N_rf行、K列的等效信道,W是N_rf行、K列。发送信号是W乘以符号向量,所以功率约等于每个用户的列范数平方乘以总功率再除以K。最好做一个功率归一化,否则仿真结果会比理论值高出一大截。
3.2 全息MIMO下频率效率和能量效率的权重不同
频谱效率的单位是bit/s/Hz。在多用户场景中,总频谱效率是所有用户的和。但是实际系统更关心的是“小区边缘用户的保障速率”以及“单元/射频链路数量的成本效率”。我习惯在仿真结果图里同时画出三组曲线:
- 总频谱效率(sum-rate)
- 每个用户的平均频谱效率
- 第5百分位用户速率(对应边缘用户体验)
如果不关心边缘用户,只看平均速率,那么在全息表面上做过于集中的波束会造成用户间严重的“饿死”现象。这个现象在仿真里表现为:某个用户信道质量特别好,ZF给它分配了极高功率,其他用户几乎为零。为了抑制这种情况,我用的是分数功率分配:按信道增益的平方分配功率,而不是平均分。
matlab复制power_weights = (sum(abs(H).^2, 1))'; % 每个用户的信道增益
power_weights = power_weights / sum(power_weights) * P_t;
SINR = (power_weights' .* abs(diag(H'*W_norm)).^2) ./ noise_power;
这里的diag取的是对角项,表示直达信号增益。干扰项通过矩阵计算得到,然后求每个用户的速率。如果想要严格正确,还是先把等效SINR公式写成矩阵形式,再用逐用户循环去算,避免维度错误。
3.3 蒙特卡洛循环里统计顺序很重要
频谱效率分析需要一个统计平均过程。因为用户在每次快照中的位置、信道衰落都是随机的,单次仿真的曲线毛刺很多。我的做法是外层遍历SNR,内层跑1000个用户掉落快照,每次记录速率,最后取平均。如果SNR点有8个,快照数8000,对于32*32阵列的信道生成,Matlab运行时间并不长。
parfor 可以用来加速不同的SNR蒙特卡洛批次。但要注意随机数种子管理,否则每次并行结果可能相关。我习惯在主循环开始前用rng(42)固定种子,确保每隔一段时间跑出来的结果可复现。
4. 仿真参数设计与结果解读:我从六组对照实验中学到的事
4.1 基础参数怎么设置
我这里给出一个用于复现运行的参数模板,直接套到你的代码工程里基本不会跑飞。
| 参数 | 数值 | 说明 |
|---|---|---|
| 载波频率 | 28 GHz | 毫米波频段 |
| 表面阵元间距 | 0.25波长 | 亚波长间距,体现全息口径优势 |
| x方向单元数 | 16 | 对应实际平面尺寸约4个波长 |
| z方向单元数 | 16 | 共256个辐射单元 |
| 射频链路数 | 16 | 后续可调到32 |
| 用户数 | 8 | 单天线用户 |
| 莱斯因子(视距) | 10 dB | 直射径为主 |
| 噪声功率 | -90 dBm | 根据带宽20 MHz计算 |
| 发送总功率 | 20~40 dBm | SNR区间需要扫参 |
| 路径损耗指数 | 3.5 | 城市环境微蜂窝 |
| 参考距离1m处损耗 | -60 dB | 由频率和天线增益推算 |
这些参数结合了毫米波信道特性和全息表面小型化的特点。如果你想要在较低频段,比如3.5 GHz,需要重新计算路径损耗和阵列尺寸。
4.2 单元间距从半波长压到四分之一波长会带来什么
我做了三组对比:同样的256个单元,单元间距分别是半波长、三分之一波长、四分之一波长。结果是:
- 半波长时,阵列物理尺寸最大,但波束指向精度和波束扫描副瓣电平和预期一致。
- 四分之一波长时,阵列物理尺寸缩小到接近一半,但全息表面可用单元密度更高,同一物理口径内可布局的“可控单元”更多。
- 频谱效率方面,在射频链路数固定为16的情况下,四分之一波长的频谱效率在低信噪比略低,高信噪比却略高。原因是更紧密的单元间距提高了近场耦合度,方向图更平滑,反而有利于波形成形。
这里要特别说明:仿真时单元间距变小不会自动提升频谱效率,除非你同时增加单元数或调整波束成形算法。全息表面的优势来自于“物理口径内可采样的电磁场点数增加”,也就是空间采样密度提高。如果只看总单元数,四分之一波长用256个单元占的面积会小很多,这时频谱效率可能反而低于半波长用256个单元。
4.3 射频链路数有限时,增加表面单元数不一定有意义
我尝试过固定16射频链路,把表面单元从64增加到256再到1024,总频谱效率的变化一开始还明显,后期变得平缓。原因是波束选择矩阵只能从大量单元中选出16个有效方向,相当于大量单元在“协同”,而真正带信息的空间自由度依旧受限于射频链路数。
如果你想通过仿真说明全息MIMO表面的价值,不能只展示“单元数越多越好”,而是要展示“同等物理口径下,全息表面单元密度提升带来的波束合成精度提升”。这个结论在论文里更经得起推敲。
在编写代码时,注意保持真实的CFO(载波频率偏移)干扰和信道估计误差为0,只关注发射端已知理想信道假设下的上限。实际系统需要引入导频开销和信道估计误差,会让频谱效率曲线下降。
5. 信道建模与频谱效率仿真中,我踩过的三个坑
5.1 天线间距用错了波长,导致波束图混乱
在某次写入路径模型时,LoS径要建模为视距方向,但信号的行程差我算成了半波长整数倍,结果把多用户之间的干扰算错了。后来我在导向向量里保留了每个单元的相位差,并用手算角度去核验,才排查出来。这件事给我的教训是:每一个角度路径都要先算理论阵列响应峰值方向,再作为生成信道的一部分去复用。否则一旦代码整体写完,定位错误会消耗大量时间。
5.2 迫零预编码矩阵求逆时出现奇异矩阵
用户数等于射频链路数时,可能由于用户之间角度太接近,导致信道矩阵的列相关性很高,求逆结果非常大。频谱效率会出现个别点离谱峰值。我处理的方法是:给信道矩阵加一个小对角线噪声项再做正则化:
matlab复制W = H / (H'*H + 0.1 * eye(K)); % 正则化迫零
这个系数0.1需要根据噪声功率调整。更正规的做法是使用MMSE预编码:
matlab复制W = H / (H'*H + (K*noise_power/P_t) * eye(K));
实际仿真中MMSE预编码比ZF在低信噪比下更稳,高信噪比则二者接近。这也是我踩过坑后建议的第一步替换方案。
5.3 相位噪声和用户同步相关的坑(仿真常见的伪影)
如果你在信道生成时给每个用户加了一个随机初始相位,但这些随机相位不随时间重播,那么多次蒙特卡洛研究时随机相位会造成结果偏置。正确做法是每个用户对应一个固定的相位种子,只随着新的信道快照变化。否则用户独立性的假设会被破坏,造成频谱效率的统计值高估或低估。你在复现代码时如果发现不同随机种子下sum-rate出现2 dB以上的波动,大概率是相位种子没有处理好。
6. 从全息MIMO表面到更广义的仿真扩展
6.1 把全息表面替换成智能反射面(RIS)辅助通信
很多项目标题里提到“全息MIMO表面”后,顺手也会做RIS辅助通信。两者有联系,但并不同一:RIS往往本身没有射频链路,只是控制反射系数把信号反射给用户;全息MIMO表面通常指基站侧有源阵列,或者至少部分是接收馈电的发射口径。
如果要从全息MIMO表面仿真扩展到RIS场景,可以做三处修改:
- 把发射源和RIS之间的信道加进去,模型变成源节点-RIS-用户级联。
- RIS单元响应不再是发射导向向量,而是反射导向向量,且需要考虑双倍路径损耗。
- 频谱效率计算要考虑基站功率约束和RIS无源反射约束的耦合。
在Matlab工程里,通常先构建一个源节点到RIS的信道矩阵G,再构建RIS到用户的信道矩阵H2,然后等效用户信道是H2' * Theta * G,其中Theta是RIS对角线反射系数矩阵。求解Theta的优化会成为额外复杂问题。
6.2 从远场平面波前扩展到近场球面波前
另一个可以继续做的方向是近场通信。传统信道建模假设基站和用户之间的距离远大于阵列孔径,波前是平面的。但全息MIMO表面物理孔径有时较大,用户距离又近,这时不能再用平面波模型,而要考虑每个表面单元到用户位置的独立距离。
这改动在Matlab中不会太大:导向向量里不再是统一角度,而是逐单元计算到用户的欧氏距离,再生成相位。这时的信道向量长度不变,但相位结构与UPA完全不同。近场条件下可能引入额外的聚焦增益,这是目前研究中比较热的方向,也更容易出有意思的图表。
6.3 代码工程化建议:模块划分和结果导出
源码工程我习惯按下面结构组织:
text复制main_multi_user_holographic.m % 主脚本,调用各模块并画图
+models/channel_generator.m
+models/precoding.m
+simulation/snapshot_sim.m
+utils/upa_array_response.m
+utils/pathloss_model.m
+plot/plot_spec_eff_vs_snr.m
这样的好处是调参时不用到处找代码。主脚本里只留下参数区和几个for循环,复杂逻辑都放函数里,也方便改造成RIS或者近场版本。
至于结果导出,我每次跑完都把sum_rate和per_user_rate保存为.mat文件,再用一个独立绘图脚本整理图,避免为了某一张图重复跑全部仿真。否则每调一次图例和坐标范围就要重算8000次蒙特卡洛,太浪费时间。
7. 关键仿真结果长什么样:一些可以“抄作业”的图表判断标准
7.1 sum-rate曲线的正常形态
理想情况下,总频谱效率随SNR近似线性增长,但到高SNR会因为干扰受限或功率分配饱和而弯曲。若你用迫零预编码,高SNR下曲线仍会随对数增长,但斜率会减小。用MMSE预编码时,低SNR曲线更高,高SNR时它与ZF趋于重合。
如果仿真结果里sum-rate在高SNR出现下降,基本能断定是数值问题:大概率是矩阵条件数过大,或者功率分配权重没有归一化。
7.2 不同用户数下的频谱效率趋势
我跑过用户数K=4、8、16,射频链路数固定为16。结果曲线如下:
- K=4:每个用户获得更多功率,但用户分集增益较少,总频谱效率在低信噪比高一些。
- K=8:总频谱效率在高信噪比明显提升,边缘用户体验得到保障。
- K=16:总频谱效率继续提升,但由于空间自由度已用完,用户间的干扰增加,边缘用户速率急剧下降。
在实际部署中,K = N_rf并不一定最佳。如果关注的是总和速率,K接近N_rf较好;如果关注的是qos公平性,K取N_rf/2更合理。你可以调整用户调度算法来兼顾二者。
7.3 频谱效率与单元数/成本之间的权衡
在交付项目或写报告时,导师或客户常问一个问题:全息MIMO表面投入这么多单元,到底值不值?我会用两个图来回答:固定物理口径,把单元数从64变成256,频谱效率能提升多少;固定单元总数,把射频链路数从8变成32,频谱效率能提升多少。通常情况下后者提升更明显,这也说明硬件瓶颈更多在于射频链路而非天线单元数。
8. 一些可以直接用到你仿真里的实用建议
8.1 将你的信道模型“可视化”检查
不要裸跑频谱效率。在生成多个用户信道后,我建议先画出所有用户的角度谱(即用DFT码本投影信道增益),观察用户是否在角度域分得开。
如果两个用户角度太接近,频谱效率会一直上不去,这不是算法问题,而是用户调度的先天限制。如果要在报告中说明全息表面的优势,应当让不同用户分布在不同的角度簇。
8.2 使用低复杂度的用户调度算法
如果用户数很多(比如32),可以做一个简单贪心调度:先选信道范数最大的用户,选出后更新剩余候选用户与已选集的干扰度量,一路选够N_rf个用户。这个算法代码量少,效果也不错。
matlab复制selected = false(1, K);
Hsel = [];
for step = 1:N_rf
scores = zeros(1, K);
for u = 1:K
if ~selected(u)
Htest = [Hsel, H(:,u)];
scores(u) = log(det(eye(N_rf) + snr * Htest*Htest' / K));
end
end
[~, idx] = max(scores);
selected(idx) = true;
Hsel = [Hsel, H(:,idx)];
end
这里每次调度后要保证矩阵的伪逆稳定,所以对信道矩阵做一次条件数检查比较好。调度过程本身对频谱效率的分析结果影响很大,忽略它会导致你多用户分析的结论失真。
8.3 把归一化功率约束写清楚
迫零预编码的功率归一化有两种常见方式:总功率归一化(所有用户发送向量之和的Frobenius范数为1)或逐用户发射功率归一化。在多用户全息MIMO中,我推荐前者,因为它更贴近基站总功率有限的实际情况。实现时:
matlab复制W = W ./ norm(W, 'fro') * sqrt(P_t);
如果你用逐用户归一化,那么每个用户占用的发射功率相同,更适用于等速率服务的公平场景。两种方法都跑一遍,你会找到各自的适用条件。
9. 从我这边视角再看全息MIMO表面:它可能不是万能但值得研究
我自己在Matlab中做完全套仿真之后,最大的感悟是:全息MIMO表面这项技术处于阵列天线和智能超表面之间,概念很前沿,但仿真它不需要把物理细节全部拉满。理解了信道建模的基本维度、射频链路约束和用户调度策略,就能得到有效结论。
对于刚接触这个方向的你,我的直接建议是:先把传统MIMO仿真跑通,然后修改阵列响应函数和单元间距,再加入大量可控单元,慢慢观察频谱效率的变化。不要一上来就复制顶会代码跑一堆结果,那样出了问题很难排查。
全息MIMO表面的更多价值在于它可以动态生成任意形状的波束,在波束空间设计中具备更大的自由度。如果你深入研究,会发现它和基于压缩感知的混合波束成形有很强的关联,核心都在于高维天线空间和低维射频链路之间的映射。
在实际复现本文思路时,如果信道建模的复杂度让你吃力,可以先从高斯独立同分布信道开始对比,再切到本文给出的空间相关UPA信道。你会发现两个模型下的频谱效率差异巨大,从而更理解为什么信道建模在通信仿真里是第一个要严谨对待的环节。
平时跑这种系统级仿真,我最后总会把数值结果和理论近似再对照一次。比如在低信噪比下,多用户系统倾向于功率受限,总频谱效率应近似等于N_rf * log2(1 + SNR / N_rf),在高信噪比下则接近干扰受限模型。这个粗略的理论值能帮你快速判断仿真代码是否异常,而不是等整条曲线画出来后才发现算错了。希望这些经验能让你在写自己的全息MIMO表面仿真时少走几步弯路。
