@@ -62,21 +62,23 @@ def snr_est_test(model, snr_target, h, Nw, test_S1=False):
62
62
# matrix of received pilots plus noise samples
63
63
Pcn_hat = h * Pcn + n
64
64
65
+ Rcn_hat_genie = np .abs (h )* Pcn + n
66
+ Ns = model .Ns + 1
67
+ rx_sym_pilots = torch .zeros ((1 ,1 ,Nw * Ns ,Nc ), dtype = torch .complex64 )
68
+ rx_sym_pilots [0 ,0 ,::Ns ,:] = torch .tensor (Pcn_hat )
69
+ rx_pilots = receiver .est_pilots (rx_sym_pilots , Nw - 1 , Nc , Ns )
70
+ rx_pilots = rx_pilots .cpu ().detach ().numpy ()
71
+ rx_phase = np .angle (rx_pilots )
72
+ Rcn_hat_est = Pcn_hat * np .exp (- 1j * rx_phase )
73
+
65
74
# phase corrected received pilots
66
75
genie_phase = not args .eq_ls
76
+
67
77
if genie_phase :
68
- Rcn_hat = np . abs ( h ) * Pcn + n
78
+ Rcn_hat = Rcn_hat_genie
69
79
else :
70
- Ns = model .Ns + 1
71
- rx_sym_pilots = torch .zeros ((1 ,1 ,Nw * Ns ,Nc ), dtype = torch .complex64 )
72
- rx_sym_pilots [0 ,0 ,::Ns ,:] = torch .tensor (Pcn_hat )
73
- rx_pilots = receiver .est_pilots (rx_sym_pilots , Nw - 1 , Nc , Ns )
74
- rx_pilots = rx_pilots .cpu ().detach ().numpy ()
75
- rx_phase = np .angle (rx_pilots )
76
- #print(rx_phase.shape)
77
- #print(rx_phase)
78
- Rcn_hat = Pcn_hat * np .exp (- 1j * rx_phase )
79
-
80
+ Rcn_hat = Rcn_hat_est
81
+
80
82
if args .plots :
81
83
plt .figure (1 )
82
84
plt .plot (Rcn_hat .real , Rcn_hat .imag ,'b+' )
@@ -96,17 +98,25 @@ def snr_est_test(model, snr_target, h, Nw, test_S1=False):
96
98
print (f"S1: { S1 :5.2f} S1_sum: { S1_sum :5.2f} " )
97
99
98
100
# calculate S2 and SNR est
99
- S2 = np .sum (np .abs (Rcn_hat .imag )** 2 )
100
- snr_est = S1 / (2 * S2 ) - 1
101
-
102
- # actual snr as check, for AWGN should be close to snr_target, for non untity h
103
- # it can be quite different
104
-
101
+ S2_genie = np .sum (np .abs (Rcn_hat_genie .imag )** 2 )
102
+ S2_est = np .sum (np .abs (Rcn_hat_est .imag )** 2 )
103
+ if genie_phase :
104
+ snr_est = S1 / (2 * S2_genie ) - 1
105
+ else :
106
+ snr_est = S1 / (2 * S2_est ) - 1
107
+
108
+ # remove occasional illegal values
109
+ if snr_est <= 0 :
110
+ snr_est = 0.1
111
+
112
+ # actual snr for this time window as check, for AWGN should be
113
+ # close to snr_target, for non untity h it can be quite different
105
114
snr_check = np .sum (np .abs (h * Pcn )** 2 )/ np .sum (np .abs (n )** 2 )
106
- #print(f"S: {np.sum(np.abs(h*Pcn)**2):f} N: {np.sum(np.abs(n)**2)}")
107
- #print(f"snr:target {snr_target:5.2f} snr_check: {snr_check.real:5.2f} snr_est: {snr_est:5.2f}")
108
115
109
- return snr_est ,snr_check
116
+ # user supplied correction factor
117
+ snr_est *= 10 ** (args .offset / 10 )
118
+
119
+ return snr_est , snr_check , S2_genie , S2_est
110
120
111
121
# Bring up a RADAE model
112
122
latent_dim = 80
@@ -122,47 +132,79 @@ def snr_est_test(model, snr_target, h, Nw, test_S1=False):
122
132
123
133
# single timestep test
124
134
def single (snrdB , h , Nw , test_S1 ):
125
- snr_est , snr_check = snr_est_test (model , 10 ** (snrdB / 10 ), h , Nw , test_S1 )
135
+ snr_est , snr_check , S2_genie , S2_est = snr_est_test (model , 10 ** (snrdB / 10 ), h , Nw , test_S1 )
126
136
print (f"snrdB: { snrdB :5.2f} snrdB_check: { 10 * np .log10 (snr_check ):5.2f} snrdB_est: { 10 * np .log10 (snr_est ):5.2f} " )
127
137
128
138
# run over a sequence of timesteps, and return lists of each each est
129
139
def sequence (Ntimesteps , snrdB , h , Nw ):
130
140
snrdB_est_list = []
131
141
snrdB_check_list = []
142
+ NdB_genie_list = []
143
+ NdB_est_list = []
132
144
133
145
for i in range (Ntimesteps ):
134
- snr_est , snr_check = snr_est_test (model , 10 ** (snrdB / 10 ), h [i * Nw :(i + 1 )* Nw ,:], Nw )
146
+ snr_est , snr_check , S2_genie , S2_est = snr_est_test (model , 10 ** (snrdB / 10 ), h [i * Nw :(i + 1 )* Nw ,:], Nw )
135
147
snrdB_check = 10 * np .log10 (snr_check )
136
148
snrdB_est = 10 * np .log10 (snr_est )
137
- print (f"snrdB: { snrdB :5.2f} snrdB_check: { snrdB_check :5.2f} snrdB_est: { snrdB_est :5.2f} " )
149
+ NdB_genie = 10 * np .log10 (2 * S2_genie )
150
+ NdB_est = 10 * np .log10 (2 * S2_est )
151
+
152
+ print (f"snrdB: { snrdB :5.2f} snrdB_check: { snrdB_check :5.2f} snrdB_est: { snrdB_est :5.2f} NdB: { NdB_genie :5.2f} { NdB_est :5.2f} " )
153
+
138
154
snrdB_est_list = np .append (snrdB_est_list , snrdB_est )
139
155
snrdB_check_list = np .append (snrdB_check_list , snrdB_check )
156
+ NdB_genie_list = np .append (NdB_genie_list , NdB_genie )
157
+ NdB_est_list = np .append (NdB_est_list , NdB_est )
140
158
141
- return snrdB_est_list , snrdB_check_list
159
+ return snrdB_est_list , snrdB_check_list , NdB_genie , NdB_est
142
160
143
161
# sweep across SNRs
144
162
def sweep (Ntimesteps , h , Nw ):
145
163
146
164
EsNodB_check = []
147
165
EsNodB_est = []
166
+ NdB_genie = []
167
+ NdB_est = []
168
+
148
169
r = range (- 5 ,20 )
149
170
for aEsNodB in r :
150
- aEsNodB_check , aEsNodB_est = sequence (Ntimesteps , aEsNodB , h , Nw )
171
+ aEsNodB_check , aEsNodB_est , aNdB_genie , aNdB_est = sequence (Ntimesteps , aEsNodB , h , Nw )
151
172
EsNodB_check = np .append (EsNodB_check , aEsNodB_check )
152
173
EsNodB_est = np .append (EsNodB_est , aEsNodB_est )
174
+ NdB_genie = np .append (NdB_genie , aNdB_genie )
175
+ NdB_est = np .append (NdB_est , aNdB_est )
153
176
177
+ z = np .polyfit (EsNodB_check , EsNodB_est , 1 )
178
+ print (z )
179
+ EsNodB_est_fit = z [0 ]* EsNodB_check + z [1 ]
180
+
154
181
plt .figure (1 )
155
182
plt .plot (EsNodB_check , EsNodB_est ,'b+' )
183
+ plt .plot (EsNodB_check , EsNodB_est_fit ,'r' )
156
184
plt .plot (r ,r )
157
185
plt .axis ([- 5 , 20 , - 5 , 20 ])
158
186
plt .grid ()
159
187
plt .xlabel ('SNR (dB)' )
160
188
plt .ylabel ('SNR est (dB)' )
189
+
190
+ z = np .polyfit (NdB_genie , NdB_est , 1 )
191
+ print (z )
192
+ NdB_est_fit = z [0 ]* NdB_genie + z [1 ]
193
+ print (len (NdB_est ))
194
+ plt .figure (2 )
195
+ plt .plot (NdB_genie , NdB_est ,'b+' )
196
+ plt .plot (NdB_genie ,NdB_genie )
197
+ plt .plot (NdB_genie , NdB_est_fit ,'r' )
198
+ plt .grid ()
199
+ plt .xlabel ('N_genie (dB)' )
200
+ plt .ylabel ('N_est (dB)' )
201
+
161
202
plt .show ()
162
203
163
- # save test file of test points for Latex plotting in Octave radae_plots.m:est_snr_plot()
164
- test_points = np .transpose (np .array ((EsNodB_check ,EsNodB_est )))
165
- np .savetxt ('est_snr.txt' ,test_points ,delimiter = '\t ' )
204
+ if args .save_text :
205
+ # save test file of test points for Latex plotting in Octave radae_plots.m:est_snr_plot()
206
+ test_points = np .transpose (np .array ((EsNodB_check ,EsNodB_est )))
207
+ np .savetxt (args .save_text ,test_points ,delimiter = '\t ' )
166
208
167
209
parser = argparse .ArgumentParser ()
168
210
parser .add_argument ('--snrdB' , type = float , default = 10.0 , help = 'snrdB set point' )
@@ -172,8 +214,10 @@ def sweep(Ntimesteps, h, Nw):
172
214
parser .add_argument ('-T' , type = float , default = 1.0 , help = 'length of time window for estimate (default 1.0 sec)' )
173
215
parser .add_argument ('--Nt' , type = int , default = 1 , help = 'number of analysis time windows to test across (default 1)' )
174
216
parser .add_argument ('--test_S1' , action = 'store_true' , help = 'calculate S1 two ways to check S1 expression' )
175
- parser .add_argument ('--eq_ls' , action = 'store_true' , help = 'est phase from received pilots usin least square (default genie phase)' )
217
+ parser .add_argument ('--eq_ls' , action = 'store_true' , help = 'est phase from received pilots using least square (default genie phase)' )
176
218
parser .add_argument ('--plots' , action = 'store_true' , help = 'debug plots (default off)' )
219
+ parser .add_argument ('--save_text' , type = str , default = "" , help = 'path to text file to save test points' )
220
+ parser .add_argument ('--offset' , type = float , default = 0.0 , help = 'y offset correction in dB (default 0)' )
177
221
args = parser .parse_args ()
178
222
179
223
Nw = int (args .T // model .Tmf )
0 commit comments