(Water Filling)注水算法原理与实现

目录

  • 问题背景与建模
  • 问题求解
  • 算法描述
  • 算法实现
    • 方法一
    • 方法二
      • 线性搜索
      • 二分搜索
    • 测试代码
  • 总结

问题背景与建模

考虑一个多用户多输入单输出MU-MISO下行通信场景,基站端配置有 N N N根天线,其服务该小区下 K K K个单天线用户。假定信道为平坦瑞利衰落信道,记为 H ∈ C N × K \mathbf{H}\in\mathcal{C}^{N\times K} HCN×K,基站最大发射功率为 P P P。假设波束赋形采用Zero Forcing,若记
W = H ( H H H ) − 1 \mathbf{W}=\mathbf{H}(\mathbf{H}^H\mathbf{H})^{-1} W=H(HHH)1

注意 W \mathbf{W} W并不是最终的波束赋形矩阵,因为还没有考虑功率约束以及进一步的功率分配。

则第 k k k个用户的波束方向为
w ~ k = w 1 ∣ ∣ w 1 ∣ ∣ 2 \tilde\mathbf{w}_k=\frac{\mathbf{w}_1}{||\mathbf{w}_1||_2} w~k=w12w1

W ~ = [ w ~ 1 , . . . , w ~ K ] \tilde \mathbf{W}=[\tilde\mathbf{w}_1,...,\tilde\mathbf{w}_K] W~=[w~1,...,w~K],功率分配矩阵为

P = diag ( P 1 , . . . , P K ) \mathbf{P}=\text{diag}(P_1,...,P_K) P=diag(P1,...,PK)

则最终的波束赋形矩阵为
W ZF = W ~ ⋅ P \mathbf{W}_{\text{ZF}}=\tilde \mathbf{W}\cdot\sqrt\mathbf{P} WZF=W~P

若不考虑功率分配,显然 ∀ k ,   P k = P / K \forall k,\ P_k=P/K k, Pk=P/K

若记基站发送的符号向量为 s = [ s 1 , . . . , s K ] \mathbf{s}=[s_1,...,s_K] s=[s1,...,sK],且满足 E [ s s H ] = I K \mathbb{E}[\mathbf{s}\mathbf{s}^H]=\mathbf{I}_K E[ssH]=IK,则用户 k k k接收到的信号为
y k = h k H w k s k + n k y_k=\mathbf{h}_k^H\mathbf{w}_ks_k+n_k yk=hkHwksk+nk

这是因为ZF完全消除了用户间干扰!此时SINR就是SNR。

而对于其他的波束赋形,如MMSE、MRT等,由于用户间干扰不能完全去除,用户 k k k的SINR里面还嵌入有其他用户的功率,本文water-filling求出的解只是对于ZF波束赋形是最优的,对于其他的beamforming, 只能说是次优和heuristic的。

其中 n k n_k nk为用户 k k k处的噪声, n k ∼ C N ( 0 ,   1 ) n_k\sim \mathcal{CN}(0,\ 1) nkCN(0, 1)。第 k k k个用户的信噪比SNR为
γ k = ∣ ∣ h k H w k ∣ ∣ 2 2 = P k ∣ ∣ h k H w ~ k ∣ ∣ 2 2 \gamma_k=||\mathbf{h}_k^H\mathbf{w}_k||_2^2=P_k||\mathbf{h}_k^H\tilde\mathbf{w}_k||_2^2 γk=hkHwk22=PkhkHw~k22

k k k个用户的信息速率为
R k = log ⁡ ( 1 + γ k ) R_k=\log(1+\gamma_k) Rk=log(1+γk)

实际上这是肯定不可能达到的,只具有理论分析上的意义。

现在希望合理的分配功率来使得加权和速率最大,即
max ⁡ P 1 , . . . , P K ∑ k = 1 K α k R k s.t. ∑ k = 1 K P k = P P k ≥ 0 \max_{P_1,...,P_K}\quad \sum_{k=1}^K\alpha_kR_k\\ \\ \text{s.t.}\quad \sum_{k=1}^KP_k=P\\ P_k\geq 0 P1,...,PKmaxk=1KαkRks.t.k=1KPk=PPk0

上面直接让各用户功率之和等于最大发射功率,即让本来的不等式约束变为严格等于。这是因为最优解必然是满足这一点的。

问题求解

∑ k = 1 K α k R k = ∑ k = 1 K α k log ⁡ ( 1 + P k ∣ ∣ h k H w ~ k ∣ ∣ 2 2 ) = ∑ k = 1 K α k log ⁡ ( 1 ∣ ∣ h k H w ~ k ∣ ∣ 2 2 + P k ) + ∑ k = 1 K α k log ⁡ ∣ ∣ h k H w ~ k ∣ ∣ 2 2 \begin{aligned} &\sum_{k=1}^{K} \alpha_kR_k\\ &=\sum_{k=1}^K\alpha_k\log(1+P_k||\mathbf{h}_k^H\tilde\mathbf{w}_k||_2^2)\\ &=\sum_{k=1}^K\alpha_k\log(\frac{1}{||\mathbf{h}_k^H\tilde\mathbf{w}_k||_2^2}+P_k)+\sum_{k=1}^K\alpha_k\log||\mathbf{h}_k^H\tilde\mathbf{w}_k||_2^2 \end{aligned} k=1KαkRk=k=1Kαklog(1+PkhkHw~k22)=k=1Kαklog(hkHw~k221+Pk)+k=1KαkloghkHw~k22

定义
L k = 1 ∣ ∣ h k H w ~ k ∣ ∣ 2 2 L_k=\frac{1}{||\mathbf{h}_k^H\tilde\mathbf{w}_k||_2^2} Lk=hkHw~k221

则优化问题变为
max ⁡ P 1 , . . . , P K ∑ k = 1 K α k log ⁡ ( L k + P k ) s.t. ∑ k = 1 K P k = P P k ≥ 0 \max_{P_1,...,P_K}\quad \sum_{k=1}^K\alpha_k\log(L_k+P_k)\\ \\ \text{s.t.}\quad \sum_{k=1}^KP_k=P\\ P_k\geq 0 P1,...,PKmaxk=1Kαklog(Lk+Pk)s.t.k=1KPk=PPk0

可以看到与大多地方介绍注水算法有些许不同,此处其实是更一般的情况,即不同用户的权重或者priority是不同的。
该问题是凸优化问题,且Slater条件满足,此时KKT条件是最优性的充要条件。
拉格朗日函数为
L = − ∑ k = 1 K α k log ⁡ ( L k + P k ) − ∑ k = 1 K λ k P k + μ ( ∑ k = 1 K P k − P ) L=-\sum_{k=1}^K\alpha_k\log(L_k+P_k)-\sum_{k=1}^K\lambda_kP_k+\mu\left(\sum_{k=1}^KP_k-P\right) L=k=1Kαklog(Lk+Pk)k=1KλkPk+μ(k=1KPkP)

互补松弛条件为
λ k P k = 0 \lambda_kP_k=0 λkPk=0

平稳性条件为
− α k L k + P k − λ k + μ = 0 -\frac{\alpha_k}{L_k+P_k}-\lambda_k+\mu=0 Lk+Pkαkλk+μ=0

所以有
( μ − α k L k + P k ) P k = 0 \left(\mu-\frac{\alpha_k}{L_k+P_k}\right)P_k=0 (μLk+Pkαk)Pk=0

μ ≥ α k L k \mu\geq \frac{\alpha_k}{L_k} μLkαk时,必然有 P k = 0 P_k=0 Pk=0;

μ < α k L k \mu< \frac{\alpha_k}{L_k} μ<Lkαk时,有
P k = α k μ − L k P_k=\frac{\alpha_k}{\mu}-L_k Pk=μαkLk

换句话说,

L k α k ≥ 1 μ \frac{L_k}{\alpha_k}\geq \frac{1}{\mu} αkLkμ1时, P k α k = 0 \frac{P_k}{\alpha_k}=0 αkPk=0

L k α k < 1 μ \frac{L_k}{\alpha_k}< \frac{1}{\mu} αkLk<μ1时, P k α k = 1 μ − L k α k \frac{P_k}{\alpha_k}=\frac{1}{\mu}-\frac{L_k}{\alpha_k} αkPk=μ1αkLk

算法描述

上面的结果可以描述为一个往容器中注水的过程。考虑如下这样一个“水槽”(2维)
(Water Filling)注水算法原理与实现_第1张图片
k k k个台阶的宽即为 α k \alpha_k αk,高(离槽底)为 L k / α k L_k/\alpha_k Lk/αk,对应的面积为 L k L_k Lk,那么功率分配的过程就是将功率P像是注水一样进行分配,倒入这个水槽。若台阶太高(信道太差),则该台阶上不会分配到水。对于非加权的简单情况,每一个台阶的宽都相等,为单位长度。显然注水之后的水位线即为
1 μ \frac{1}{\mu} μ1

上面的图其实是按照不同用户的 L k / α k L_k/\alpha_k Lk/αk进行了排序。实际实现时,可视采用的算法决定是否进行排序。

算法实现

可以看出,如果我们能知道最终的水位线 1 / μ 1/\mu 1/μ,那么问题就十分简单,只需要根据每个用户的台阶高度决定是否给该用户分配功率以及分配多少。但是这个水位线并非提前就知道的。所以实际实现时有两个方法

  • 先明确水位线,然后分配
  • 不具体求水位线,而是将用户按 L k / α k L_k/\alpha_k Lk/αk进行排序,然后确定哪些用户需要注水

方法一

其算法流程为:

K = { 1 , . . . , K } \mathcal{K}=\{1,...,K\} K={1,...,K}

1 / μ ^ = ( P + ∑ k ∈ K L k ) / ∑ k ∈ K α k 1/\hat\mu=(P+\sum_{k\in\mathcal{K}}L_k)/\sum_{k\in\mathcal{K}} \alpha_k 1/μ^=(P+kKLk)/kKαk(假设每个用户都分配)

k ^ = arg ⁡ max ⁡ k ∈ K L k / α k \hat k =\arg\max_{k\in \mathcal{K}}L_k/\alpha_k k^=argmaxkKLk/αk

while L k ^ / α k ^ ≥ 1 / μ ^ \text{while}\quad L_{\hat k}/\alpha_{\hat k}\geq1/\hat \mu whileLk^/αk^1/μ^

K = K − k ^ \quad \quad \mathcal{K}=\mathcal{K}-\hat k K=Kk^

1 / μ ^ = ( P + ∑ k ∈ K L k ) / ∑ k ∈ K α k \quad \quad 1/\hat\mu=(P+\sum_{k\in\mathcal{K}}L_k)/\sum_{k\in\mathcal{K}} \alpha_k 1/μ^=(P+kKLk)/kKαk

k ^ = arg ⁡ max ⁡ k ∈ K L k / α k \quad \quad \hat k =\arg\max_{k\in \mathcal{K}}L_k/\alpha_k k^=argmaxkKLk/αk

于此便可求出最终的水位线 1 / μ 1/\mu 1/μ,有了水位线那么分配就很简单了。基于上述方法的MATLAB实现代码如下:

function palloc_matrix = water_filling1(loss, P, A)
% loss, Kx1向量,即L
% P, 要分配的总功率
% A, 对角阵,即权重alpha
% palloc_matrix, 对角阵,功率分配结果,迹等于P

	K = length(loss); % 用户数
    
	w = diag(A); % width, 台阶宽度
	h = loss./w; % height, 台阶高度
	
    allo_set = 1:K; % 初始化要注水用户的索引集合
    level = (P+sum(loss(allo_set>0)))/sum(w(allo_set>0)); % “虚拟”水位线
    [h_hat, k_hat] = max(h(allo_set>0));
    
    while h_hat>=level
        
        allo_set(k_hat) = -1;
        level = (P+sum(loss(allo_set>0)))/sum(w(allo_set>0)); % “虚拟”水位线
        [h_hat, k_hat] = max(h(allo_set>0));
    
    end
    
    palloc_matrix = zeros(K);
    for k = 1:K
        if allo_set(k)>0
            palloc_matrix(k, k) = (level - h(k))*w(k);
        end
    end
    
end

方法二

(Water Filling)注水算法原理与实现_第2张图片
根据 L k / α k L_k/\alpha_k Lk/αk进行升序排序,可以确定最后一个需要注水的索引,然后对其及其之前的用户进行注水。首先给出排序后第 n n n个台阶要注水的判断依据:
∑ j = 1 n − 1 α j × L n α n − ∑ j = 1 n − 1 L j > P \sum_{j=1}^{n-1}\alpha_j \times \frac{L_n}{\alpha_n}-\sum_{j=1}^{n-1}L_j>P j=1n1αj×αnLnj=1n1Lj>P

注意上式中的下标是排序后的,代码实现时需注意。

有了这个判断依据之后,便可以通过线性搜索或是二分搜索来确定最后一个要注水的台阶。

线性搜索

function palloc_matrix = water_filling2(loss, P, A)
	
	K = length(loss);
    
	w = diag(A); % 台阶宽度
	h = loss./w; % 台阶高度
	
	[h_sorted, h_idx] = sort(h); % 根据台阶高度升序排序
	w_sorted = w(h_idx);
    
    % 线性搜索,从后往前确定最后一个需要注水的台阶
    for i = K:-1:1
        
        w_tmp = sum(w_sorted(1:i-1)); % 当前台阶前面所有台阶的宽度之和
        h_tmp = h_sorted(i); % 当前台阶的高度
        
        % 把当前台阶之前的台阶注水到与当前台阶同高还有剩余水
        if w_tmp*h_tmp-sum(h_sorted(1:i-1).*w_sorted(1:i-1))<P
            idx = i;
            break;
        end
        
    end
    
    w_filled = sum(w_sorted(1:idx)); % 需要注水的所有台阶的总宽度
    h_filled = (P+sum(h_sorted(1:idx).*w_sorted(1:idx)))/w_filled; % 最终的水位线
	
	p_allocate = zeros(1, K);
    p_allocate(1:idx) = w_sorted(1:idx).*(h_filled-h_sorted(1:idx));
	
    % 恢复原来顺序
    [~, back_idx] = sort(h_idx);
    p_allocate = p_allocate(back_idx);
    
    palloc_matrix = diag(p_allocate);
    
end

二分搜索

function palloc_matrix = water_filling3(loss, P, A)
	
	K = length(loss);
    
	w = diag(A);
	h = loss./w;
	
	[h_sorted, h_idx] = sort(h);
	w_sorted = w(h_idx);
    
    % 二分搜索
    
    % 对最后一个台阶单独讨论
    if sum(w_sorted(1:K-1))*h_sorted(K)-sum(h_sorted(1:K-1).*w_sorted(1:K-1))<P
        idx = K;
    else
        idx_max = K;
        idx_min = 1;

        idx = -1;

        while 1
            idx_mid = floor(.5*(idx_max+idx_min));
            w_tmp = sum(w_sorted(1:idx_mid-1));
            h_tmp = h_sorted(idx_mid);
            if w_tmp*h_tmp-sum(h_sorted(1:idx_mid-1).*w_sorted(1:idx_mid-1))<P
                idx_min = idx_mid;
            else
                idx_max = idx_mid;
            end
            if idx_min+1 == idx_max
                idx = idx_min;
                break
            end
        end
    end
    
    w_filled = sum(w_sorted(1:idx));
    h_filled = (P+sum(h_sorted(1:idx).*w_sorted(1:idx)))/w_filled;
	
	p_allocate = zeros(1, K);
    p_allocate(1:idx) = w_sorted(1:idx).*(h_filled-h_sorted(1:idx));
	
    [~, back_idx] = sort(h_idx);
    p_allocate = p_allocate(back_idx);
    
    palloc_matrix = diag(p_allocate);
    
end

测试代码

while 1
    
    K = 4;
    P = 3;
    alpha = abs(rand(K, 1));
    A = diag(alpha);
    loss = abs(randn(K,1));
    
    % 如未安装CVX,将该代码段注释掉
    %=============================================
    cvx_begin quiet

        variable p(K)
        minimize -sum(alpha.*log(loss+p))
        subject to
            0<=p
            sum(p)==P

    cvx_end
    %=============================================

    p
    p1 = diag(water_filling1(loss,P, A))
    p2 = diag(water_filling2(loss,P, A))
    p3 = diag(water_filling3(loss,P, A))
    
end

总结

本文以加权和速率为背景引出了一般化的注水算法的问题背景,之后从KKT条件导出了该问题解的特点,该特点即表现为一个注水过程。对于本文描述的有加权的情况,形象的,每个用户对应的“台阶”宽度是不一样的,台阶越宽,表示其权重越高。最后给出了实现算法即MATLAB代码。

值得注意的是,本文前面提到,该结果是在ZF预编码的前提下推导得到的,也就是说注水算法得到的功率分配结果是ZF预编码下的最优分配方案,但对于其他预编码,如MRT、MMSE,只是次优的。

你可能感兴趣的:(通信与信息论,优化知识)