-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcb_bsw_vs_minimum_snr.py
225 lines (167 loc) · 8.24 KB
/
cb_bsw_vs_minimum_snr.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import numpy as np
import matplotlib.pyplot as plt
import scenario.common as cmn
from environment import RisProtocolEnv, command_parser, NOISE_POWER_dBm, TX_POW_dBm, T, OUTPUT_DIR, TAU, BANDWIDTH, NUM_PILOTS
import os
from matplotlib import rc
##################################################
# Parameters
##################################################
# Seed random generator
np.random.seed(42)
# Define transmit power [mW]
tx_power = cmn.dbm2watt(TX_POW_dBm)
# Get noise power
noise_power = cmn.dbm2watt(NOISE_POWER_dBm)
# For grid mesh
num_users = int(1e5)
# Parameter for saving datas
prefix = 'cb_bsw_opt_kpi'
# Setup option
setups = ['ob-cc', 'ib-wf']
# Define range of minimum SNR
minimum_snr_range_dB = np.linspace(-6, 30, 50)
minimum_snr_range = cmn.db2lin(minimum_snr_range_dB)
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
# The following parser is used to impose some data without the need of changing the script (run with -h flag for
# help) Render bool needs to be True to save the data If no arguments are given the standard value are loaded (
# see environment) datasavedir should be used to save numpy arrays
render, side, name, datasavedir = command_parser()
prefix = os.path.join(datasavedir, prefix + name)
# Build environment
env = RisProtocolEnv(num_users=num_users, side=side)
##############################
# Generate DFT codebook of configurations
##############################
# Define fundamental frequency
fundamental_freq = np.exp(-1j * 2 * np.pi / env.ris.num_els)
# Compute DFT matrix
J, K = np.meshgrid(np.arange(env.ris.num_els), np.arange(env.ris.num_els))
DFT = np.power(fundamental_freq, J * K)
# Compute normalized DFT matrix
DFT_norm = DFT / np.sqrt(env.ris.num_els)
# Get the channels:
# ur - user-ris
# rb - ris-bs
h_ur, g_rb, _ = env.return_separate_ris_channel()
# Squeeze out
g_rb = np.squeeze(g_rb)
##############################
# Codebook-based
##############################
codebook_flexi = DFT_norm.copy()
index_selection = np.arange(0, 100, 2)
codebook_fixed = DFT_norm.copy()[index_selection, :]
num_configs = len(index_selection)
# Generate noise realizations
noise_ = (np.random.randn(num_users, env.ris.num_els) + 1j * np.random.randn(num_users, env.ris.num_els)) / np.sqrt(2)
# Compute the equivalent channel
h_eq_cb_flexi = (g_rb.conj()[np.newaxis, np.newaxis, :] * codebook_flexi[np.newaxis, :, :] * h_ur[:, np.newaxis, :]).sum(axis=-1)
# Compute the equivalent channel
h_eq_cb_fixed = (g_rb.conj()[np.newaxis, np.newaxis, :] * codebook_fixed[np.newaxis, :, :] * h_ur[:, np.newaxis, :]).sum(axis=-1)
# Generate some noise
var = noise_power / NUM_PILOTS
bsw_noise_ = np.sqrt(var) * noise_
# Compute the SNR of each user when using CB scheme
sig_pow_cb_flexi = tx_power * np.abs(h_eq_cb_flexi) ** 2
sig_pow_noisy_cb_flexi = np.abs(np.sqrt(tx_power) * h_eq_cb_flexi + bsw_noise_) ** 2
sig_pow_cb_fixed = tx_power * np.abs(h_eq_cb_fixed) ** 2
sig_pow_noisy_cb_fixed = np.abs(np.sqrt(tx_power) * h_eq_cb_fixed + bsw_noise_[:, index_selection]) ** 2
snr_cb_flexi = sig_pow_cb_flexi / noise_power
snr_cb_hat_flexi = sig_pow_noisy_cb_flexi / noise_power
snr_cb_fixed = sig_pow_cb_fixed / noise_power
snr_cb_hat_fixed = sig_pow_noisy_cb_fixed / noise_power
# Prepare to store flexible rate
se_flex = np.zeros((minimum_snr_range.size, num_users))
se_fixed = np.zeros((minimum_snr_range.size, num_users))
n_configurations_flex = np.zeros((minimum_snr_range.size, num_users))
# Go through all minimum SNR values
for ms, minimum_snr in enumerate(minimum_snr_range):
# Go through all users (FLEXI)
for uu in range(num_users):
# Get the first case in which this is true
mask = snr_cb_hat_flexi[uu] >= minimum_snr
if np.sum(mask) == 0:
n_configurations_flex[ms, uu] = -1
continue
# Get the index of the first occurrence
index = np.argmax(mask)
# Store results
se_flex[ms, uu] = np.log2(1 + minimum_snr) if snr_cb_flexi[uu, index] > minimum_snr else 0.
n_configurations_flex[ms, uu] = index + 1
# Go through all users (FIXED)
for uu in range(num_users):
# Check if there is an outage
mask = snr_cb_hat_fixed[uu] >= minimum_snr
if np.sum(mask) == 0:
continue
# Get the index of the highest snr satisfying the constraint
index = np.argmax(snr_cb_hat_fixed[uu] * mask)
# Store results
se_fixed[ms, uu] = np.log2(1 + minimum_snr) if snr_cb_fixed[uu, index] > minimum_snr else 0.
## Varying the frame duration
tau_plot = [30, 60, 90]
opt_kpi_flexi = np.zeros((len(TAU), len(setups)))
opt_kpi_fixed = np.zeros((len(TAU), len(setups)))
for tt, total_tau in enumerate(TAU):
if total_tau in tau_plot:
# Prepare figure
fig, axes = plt.subplots(nrows=len(setups))
for ss, setup in enumerate(setups):
# File name
datafilename = 'data/opt_ce_vs_tau_' + setup + '.npz'
# Load data
rate = np.squeeze(np.load(datafilename)['rate'][TAU == total_tau]) * BANDWIDTH / 1e6
if total_tau in tau_plot:
axes[ss].plot(minimum_snr_range_dB, np.mean(rate) * np.ones_like(minimum_snr_range), linewidth=1.5, color='black', label='OPT-CE')
axes[ss].set_title(setup.upper())
# Define tau_setup
if setup == 'ob-cc':
tau_setup = T
elif setup == 'ib-no':
tau_setup = 2 * T
else:
tau_setup = 3 * T
# Flexible structure
# Pre-log term
tau_alg = (2 * n_configurations_flex - 1) * T
prelog_term = 1 - (tau_setup + tau_setup + tau_alg) / total_tau
prelog_term[(prelog_term < 0) | (tau_alg < 0)] = 0
rate_cb_bsw = prelog_term * se_flex
avg_rate_cb_bsw_flexi = np.mean(rate_cb_bsw, axis=-1)
if total_tau in tau_plot:
axes[ss].plot(minimum_snr_range_dB, avg_rate_cb_bsw_flexi * BANDWIDTH / 1e6, linewidth=1.5, linestyle=':', label='CB-BSW: Flexible', color='red')
opt_kpi_flexi[tt, ss] = minimum_snr_range_dB[np.argmax(avg_rate_cb_bsw_flexi)]
# Fixed structure
# Pre-log term
tau_alg = num_configs * T
prelog_term = np.maximum(1 - (tau_setup + tau_setup + tau_alg) / total_tau, 0)
rate_cb_bsw = prelog_term * se_fixed
avg_rate_cb_bsw_fixed = np.mean(rate_cb_bsw, axis=-1)
if total_tau in tau_plot:
axes[ss].plot(minimum_snr_range_dB, avg_rate_cb_bsw_fixed * BANDWIDTH / 1e6, linewidth=1.5, linestyle='--', label='CB-BSW: Fixed', color='blue')
opt_kpi_fixed[tt, ss] = minimum_snr_range_dB[np.argmax(avg_rate_cb_bsw_fixed)]
if total_tau in tau_plot:
print(f'--- tau = {total_tau:.3f} ---')
print(f'--- setup = {setup} ---')
print('OPT-CE =', np.mean(rate))
print('CB-BSW fixed =', np.max(avg_rate_cb_bsw_fixed))
print(f'opt KPI: {minimum_snr_range_dB[np.argmax(avg_rate_cb_bsw_fixed)]:.3f}')
print('CB-BSW flexi =', np.max(avg_rate_cb_bsw_flexi))
print(f'opt KPI: {minimum_snr_range_dB[np.argmax(avg_rate_cb_bsw_flexi)]:.3f}')
print('\n')
# Plot for specific values
if total_tau in tau_plot:
cmn.printplot(fig, axes, render=render, filename=f'rate_vs_gamma0_{total_tau:.2f}', dirname=OUTPUT_DIR,
labels=[r'$\gamma_0$ [dB]', r'$R$ [Mbit/s]', r'$R$ [Mbit/s]'], orientation='vertical')
# Save optimal threshold values
opt_kpi_fixed = np.mean(opt_kpi_fixed, axis=-1)
opt_kpi_flexi = np.mean(opt_kpi_flexi, axis=-1)
##################################################
# Save data
##################################################
if render:
np.savez(prefix + str('.npz'),
fixed=opt_kpi_fixed,
flexi=opt_kpi_flexi)