问题描述:
分配总功率 P P P给 N N N个发射机,使总接收通信速率最大。
问题建模为:
m
i
n
p
−
∑
i
N
W
l
o
g
2
(
1
+
h
i
p
i
σ
2
)
s
.
t
.
∑
i
N
p
i
=
P
p
i
≥
0
\begin{aligned} &\mathop{\mathrm{min}}\limits_{\mathbf{p} }~ -\sum_{i}^N Wlog_2(1+\frac{h_i p_i}{\sigma^2}) \\ &\mathrm{s.t.}~~ \sum_{i}^Np_i=P \\ &~~~~~~~~p_i\geq 0 \end{aligned}
pmin −i∑NWlog2(1+σ2hipi)s.t. i∑Npi=P pi≥0
其中
σ
2
\sigma^2
σ2为接收机的噪声功率,
W
W
W为信道带宽,
P
P
P为发射机的总功率,
p
i
p_i
pi为分给第
i
i
i个接收机、信道增益为
h
i
h_i
hi的发射功率。
对等式约束引入一个乘子
v
∈
R
v \in \mathbb{R}
v∈R,对不等式约束引入乘子
λ
∈
R
N
\mathbf{\lambda}\in \mathbb{R}^N
λ∈RN,得到Lagrange函数
L
L
L:
L
(
p
,
λ
,
v
)
=
−
∑
i
N
W
l
o
g
2
(
1
+
h
i
p
i
σ
2
)
−
∑
i
N
λ
p
i
+
v
(
∑
i
N
p
i
−
P
)
\begin{aligned} L(\mathbf{p},\mathbf{\lambda},v)=-\sum_{i}^N Wlog_2(1+\frac{h_i p_i}{\sigma^2})-\sum_{i}^N\lambda p_i+v(\sum_{i}^Np_i-P) \\ \end{aligned}
L(p,λ,v)=−i∑NWlog2(1+σ2hipi)−i∑Nλpi+v(i∑Npi−P)
令 p ∗ \mathbf{p}^* p∗和 ( λ ∗ , v ∗ ) (\mathbf{\lambda}^*, v^*) (λ∗,v∗)分别为原问题和对偶问题的某对最优解,则得到如下KKT条件:
∑ i N p i ∗ = P p i ∗ ≥ 0 , i = 1 , . . . , N λ i ∗ ≥ 0 , i = 1 , . . . , N λ i ∗ p i ∗ = 0 , i = 1 , . . . , N − W log 2 e σ 2 / h i + p i ∗ − λ i ∗ + v ∗ = 0 i = 1 , . . . , N \begin{aligned} &\sum_{i}^Np_i^*=P\\ &p_i^*\geq 0,~i=1,...,N\\ &\lambda_i^*\geq 0,~i=1,...,N\\ &\lambda_i^* p_i^*=0,~i=1,...,N\\ &-\frac{W\log_2e}{\sigma^2/h_i+p_i^*}-\lambda_i^*+v^*=0~i=1,...,N\\ \end{aligned} i∑Npi∗=Ppi∗≥0, i=1,...,Nλi∗≥0, i=1,...,Nλi∗pi∗=0, i=1,...,N−σ2/hi+pi∗Wlog2e−λi∗+v∗=0 i=1,...,N
最优解之间满足:
p
i
∗
=
{
W
log
2
e
v
∗
−
σ
2
h
i
v
∗
<
W
log
2
e
σ
2
/
h
i
0
v
∗
≥
W
log
2
e
σ
2
/
h
i
p_{i}^*= \begin{cases} \frac{W\log_2 e}{v^*}-\frac{\sigma^2}{h_i} &v^*<\frac{W\log_2 e}{\sigma^2/h_i}\\ 0&v^*\geq \frac{W\log_2 e}{\sigma^2/h_i} \end{cases}
pi∗={v∗Wlog2e−hiσ20v∗<σ2/hiWlog2ev∗≥σ2/hiWlog2e
或者,更简洁地,
p
i
∗
=
max
{
0
,
W
log
2
e
v
∗
−
σ
2
h
i
}
p_i^*=\max \{0,\frac{W\log_2e}{v^*}-\frac{\sigma^2}{h_i}\}
pi∗=max{0,v∗Wlog2e−hiσ2}。将
p
i
∗
p_i^*
pi∗带入条件
∑
i
N
p
i
∗
=
P
\sum_{i}^Np_i^*=P
∑iNpi∗=P得到:
∑
i
N
max
{
0
,
W
log
2
e
v
∗
−
σ
2
h
i
}
=
P
\sum_i^N \max \{0,\frac{W\log_2e}{v^*}-\frac{\sigma^2}{h_i}\}=P
i∑Nmax{0,v∗Wlog2e−hiσ2}=P
方程左端是
W
log
2
e
v
∗
\frac{W\log_2e}{v^*}
v∗Wlog2e的分段线性增函数,分割点为
σ
2
/
h
i
\sigma^2/h_i
σ2/hi,因此上述方程有唯一确定的解。
上述解决问题的方法称为注水。这是因为,可以将 σ 2 / h i \sigma^2/h_i σ2/hi看做第 i i i片区域的水平线,然后对整个区域注水,使其具有深度 W log 2 e v ∗ \frac{W\log_2e}{v^*} v∗Wlog2e,所需的总水量为 ∑ i N max { 0 , W log 2 e v ∗ − σ 2 h i } \sum_i^N \max \{0,\frac{W\log_2e}{v^*}-\frac{\sigma^2}{h_i}\} ∑iNmax{0,v∗Wlog2e−hiσ2},不断注水,直至总水量为 P P P。第 i i i个区域的水位深度即为最优 p i ∗ p_i^* pi∗。
上述解需要确定水位 log 2 e v ∗ \frac{\log_2 e}{v^*} v∗log2e,编程上的思想为:
- 以最差信道的高度 log 2 e σ 2 / h w o r s t \frac{\log_2 e}{\sigma^2/h_{worst}} σ2/hworstlog2e作为水位,注水(分配功率)
- 若注水到该水位时功率有剩余,则均分剩余功率;
- 若水量不足,则移除该最差信道(即不分配功率),重复以上操作。
Python代码:
# -*- coding: utf-8 -*-
"""
2021.01.29 注水法进行功率分配
注水法代码参考 https://pyphysim.readthedocs.io/en/latest/_modules/pyphysim/comm/waterfilling.html
"""
import numpy as np
def waterfilling(Channels, TotalPower, NoisePower):
""" 注水算法进行功率分配
Channels: 信道增益
TotalPower: 待分配的总发射功率
NoisePower: 接收端的噪声功率
Returns:
Powers: optimum powers (分配的功率)
mu: water level (水位)
"""
### 降序排列信道增益
Channels_SortIndexes = np.argsort(Channels)[::-1]
Channels_Sorted = Channels[Channels_SortIndexes]
"""
计算接触最差信道的水位,对这个最差的信道分配零功率。
此后,按此水位为每个信道分配功率,
如果功率之和少于总功率,则均分剩余功率给各个信道(增加水位);
如果功率之和多于总功率,则移除最坏信道,重复操作
"""
N_Channels = Channels.size ## 总信道数
N_RemovedChannels = 0 ## 移除的信道数
## 按最差信道计算最低水位
WaterLevel = NoisePower / (Channels_Sorted[N_Channels-N_RemovedChannels-1])
Powers = WaterLevel - (NoisePower /Channels_Sorted[np.arange(0, N_Channels - N_RemovedChannels)])
## 当功率之和多于总功率时,移除最坏信道,直至总功率够分
while (sum(Powers)>TotalPower) and (N_RemovedChannels<N_Channels):
N_RemovedChannels += 1
WaterLevel = NoisePower / (Channels_Sorted[N_Channels-N_RemovedChannels-1])
Powers = WaterLevel - (NoisePower /Channels_Sorted[np.arange(0, N_Channels - N_RemovedChannels)])
## 将剩余的功率均分给各个(剩余的)信道
Power_Remine = TotalPower-np.sum(Powers)
Powers_Opt_Temp = Powers + Power_Remine/(N_Channels - N_RemovedChannels)
## 将功率分配情况按原信道顺序排列
Powers_Opt = np.zeros([N_Channels])
Powers_Opt[Channels_SortIndexes[np.arange(0, N_Channels-N_RemovedChannels)]] = Powers_Opt_Temp
WaterLevel = Powers_Opt_Temp[0] + NoisePower / Channels_Sorted[0]
return Powers_Opt, WaterLevel
if __name__ == '__main__':
""" 测试代码
"""
power_Noise = 1e-8
channels = np.random.random(10)*1e-10
alpha = power_Noise/np.array(channels)
power_Tx = 1000
powers,waterlevel = waterfilling(np.array(channels), power_Tx, power_Noise)
print(powers,waterlevel)
import matplotlib
import matplotlib.pylab as plt
# %matplotlib inline
matplotlib.rcParams.update({'font.size': 14})
buckets = channels.size
axis = np.arange(0.5,buckets+1.5,1)
index = axis+0.5
X = powers.copy()
Y = alpha+ X
# to include the last data point as a step, we need to repeat it
A = np.concatenate((alpha,[alpha[-1]]))
X = np.concatenate((X,[X[-1]]))
Y = np.concatenate((Y,[Y[-1]]))
plt.xticks(index)
plt.xlim(0.5,buckets+0.5)
# plt.ylim(0,1.5)
plt.step(axis,A,where='post',label =r'$\sigma^2/h_i$',lw=2)
plt.step(axis,Y,where='post',label=r'$\sigma^2/h_i + p_i$',lw=2)
plt.legend(loc='upper left')
plt.xlabel('Bucket Number')
plt.ylabel('Power Level')
plt.title('Water Filling Solution')
plt.show()