-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
340 lines (234 loc) · 9.82 KB
/
main.py
File metadata and controls
340 lines (234 loc) · 9.82 KB
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
import json
import math
import matplotlib.pyplot as plt
import numpy as np
import os
#
# Plotting functions
#
def square_wave_plot(data, T, total_duration, title):
t = np.arange(0, total_duration, T)
plt.step(t, data)
plt.xlabel("n (sample)")
plt.ylabel("value")
plt.xticks(t)
plt.title(title)
plt.savefig("plots/"+title+".png")
plt.close()
def iqPlot(values, title, plot_points):
plt.plot(np.real(values[:plot_points]),np.imag(values[:plot_points]), '.')
plt.title(title)
plt.xlabel("Q")
plt.ylabel("I")
plt.grid()
plt.savefig("plots/"+title+".png")
plt.close()
def plot_prn_and_boc():
fig, axis = plt.subplots(nrows=2, sharex=True, subplot_kw=dict(frameon=False)) # frameon=False removes frames
t = np.arange(0, 10, 1)
axis[0].scatter(t, PRN_SEQUENCE[:10])
axis[0].set_ylabel("value")
axis[1].set_xlabel("chip time")
axis[0].set_xticks(t)
axis[0].set_title("PRN sequence")
t = np.arange(0, 10, 0.5)
axis[1].scatter(t, BOC_SEQUENCE[:20])
axis[1].set_ylabel("value")
axis[1].set_xlabel("chip time")
axis[1].set_xticks(t)
axis[1].set_title("BOC modulated signal")
axis[0].grid()
axis[1].grid()
fig.savefig("plots/PRN_with_BOC.png")
plt.close()
#
# Quantizer function
#
def quantize_uniform(x, quant_min=-1.0, quant_max=1.0, quant_level=5):
x_normalize = (x-quant_min) * (quant_level-1) / (quant_max-quant_min)
x_normalize[x_normalize > quant_level - 1] = quant_level - 1
x_normalize[x_normalize < 0] = 0
x_normalize_quant = np.around(x_normalize)-pow(2,BIT_FOR_IQ-1)
return x_normalize_quant
#
# Function for simulation of doppler shift
#
def simulate_doppler_shift(ds_duration, input_bits, freq_min, freq_max):
total_points = ds_duration * F_S
doppler_shift_vector = []
max_length = input_bits * PRN_WITH_BOC_LENGHT /(2*CHIP_RATE-freq_max) * F_S
doppler_shift_vector = np.random.uniform(freq_min,freq_max,math.ceil(max_length/total_points))
phases_shifts_vector = []
time_list = np.arange(0, ds_duration, 1/F_S)
# Phase shift calculation
for i in range(len(doppler_shift_vector)):
if(i>0):
phases_shifts_vector.append(2*math.pi*doppler_shift_vector[i-1]*ds_duration + phases_shifts_vector[i-1])
else:
phases_shifts_vector.append(0)
# Wave generation
wave_list = []
for i in range(len(doppler_shift_vector)):
wave_list = np.concatenate((wave_list,np.cos(2*math.pi*doppler_shift_vector[i]*time_list + phases_shifts_vector[i]) + 1j * np.sin(2*math.pi*doppler_shift_vector[i]*time_list + phases_shifts_vector[i])))
return wave_list, doppler_shift_vector
#
# Function for simulation of path loss
#
def simulate_path_loss(pl_duration, input_bits, val_min, val_max, freq_max):
total_points = pl_duration * F_S
path_loss_vector = []
j = 0
max_length = input_bits * PRN_WITH_BOC_LENGHT /(2*CHIP_RATE-freq_max) * F_S
while(j<max_length):
x = np.random.uniform(val_min,val_max,1)[0]
i = 0
while(i<total_points):
path_loss_vector.append(x)
i += 1
j += i
return path_loss_vector
if __name__ == '__main__':
if(os.path.exists("output.bin")):
os.remove("output.bin")
message = open("message.bin", "rb")
codes = json.load(open("codes.json", "r"))
output_file = open("output.bin","ab")
# PRN sequences already modulated with BOC
BOC_SEQUENCE = codes['boc_sequence']
BOC_SEQUENCE_INVERSE = codes['boc_sequence_inverse']
PRN_SEQUENCE = codes['prn_sequence']
PRN_SEQUENCE_INVERSE = codes['prn_sequence_inverse']
PRN_LENGHT = codes['prn_lenght']
PRN_WITH_BOC_LENGHT = PRN_LENGHT * 2
plot_prn_and_boc()
# Chanel costants
BOLTZMANN_COSTANT = 1.3809649 * pow(10,-23)
CHIP_RATE = 1.023 * pow(10,6)
F_S = 4.092*pow(10,6) # Sampling frequency
BIT_FOR_IQ = 16
# Channel Parameters
ds_duration_default = 0.2
pl_duration_default = 0.1995
ds_freq_max_default = 5000
ds_freq_min_default = 2000
pl_val_min_default = -25
pl_val_max_default = -20
snr_default = 20
print("\n### Satellite transmitter simulator ###\n")
print("legend: [unit of measure] (default value)\n")
ds_duration = float(input("Set update period of doppler shift [s] (" + str(ds_duration_default) + "): ") or ds_duration_default) # Set update period of doppler shift (s)
pl_duration = float(input("Set update period of path loss [s] (" + str(pl_duration_default) + "): ") or pl_duration_default)
ds_freq_max = int(input("Set doppler shift max freq [Hz] (" + str(ds_freq_max_default) + "): ") or ds_freq_max_default)
ds_freq_min = int(input("Set doppler shift min freq [Hz] (" + str(ds_freq_min_default) + "): ") or ds_freq_min_default)
pl_val_min = float(input("Set path loss gain min value [dB] (" + str(pl_val_min_default) + "): ") or pl_val_min_default)
pl_val_max = float(input("Set path loss gain max value [dB] (" + str(pl_val_max_default) + "): ") or pl_val_max_default)
snr = float(input("Set SNR value [dB] (" + str(snr_default) + "): ") or snr_default)
N_0 = (pow(10,np.mean([pl_val_min,pl_val_max])/10))/pow(10,snr/10)
V_SAT = np.sqrt(pow(10,pl_val_max/10)) # Computing the saturation value of the quantizer
pathLossFlag = input("Insert Path Loss? [Y/N] (Y)")
if(pathLossFlag.lower() == "y"):
pathLossFlag = True
elif(pathLossFlag.lower() == "n"):
pathLossFlag = False
else:
pathLossFlag = True
awgnFlag = input("Insert AWGN? [Y/N] (Y)")
if(awgnFlag.lower() == "y"):
awgnFlag = True
elif(awgnFlag.lower() == "n"):
awgnFlag = False
else:
awgnFlag = True
writeOutput = input("Write IQ samples output? [Y/N] (N)")
if(writeOutput.lower() == "y"):
writeOutput = True
elif(writeOutput.lower() == "n"):
writeOutput = False
else:
writeOutput = False
## Counting previously the message bits for creating the simulation vectors
message_tmp = open("message.bin", "rb")
input_size = 0
for line in message_tmp.readlines():
input_size += len(line)
####
ds_wave_list, doppler_shift_vector = simulate_doppler_shift(ds_duration, input_size, ds_freq_min, ds_freq_max)
path_loss_vector = simulate_path_loss(pl_duration, input_size, pow(10, pl_val_min/10), pow(10,pl_val_max/10), ds_freq_max)
bit_counter = 0
boc_output = []
current_time = 0
remainder = 0
message_bits_to_plot = [] # Buffer for plotting
messagePlotFlag = True
bocPlotFlag = True
prnPlotFlag = True
while(True):
message_bit = message.read(1)
message_bits_to_plot.append(message_bit)
if(len(message_bits_to_plot)>10 and messagePlotFlag):
square_wave_plot(message_bits_to_plot, 1, len(message_bits_to_plot), "Message")
messagePlotFlag = False
boc_sequence = []
try:
int(message_bit,2)
except:
break
# Just for plotting: PRN adding
PRN_sequence = []
if(int(message_bit,2)):
PRN_sequence = PRN_SEQUENCE_INVERSE
else:
PRN_sequence = PRN_SEQUENCE
if(prnPlotFlag):
square_wave_plot(PRN_sequence[:10],1,10,"Message with PRN")
prnPlotFlag = False
# PRN and BOC modulation, the BOC(1,1) sequence already contains the PRN
if(int(message_bit,2)):
boc_sequence = BOC_SEQUENCE_INVERSE
else:
boc_sequence = BOC_SEQUENCE
if(bocPlotFlag):
square_wave_plot(boc_sequence[:10],1,10,"Message modulated with Boc(1,1)")
bocPlotFlag = False
# Doppler shift implementation
repetitions = []
for i in range(len(boc_sequence)):
index = math.floor(current_time/ds_duration)
current_time += 1/(2*CHIP_RATE+doppler_shift_vector[index])
repetitions.append(1/(2*CHIP_RATE+doppler_shift_vector[index])*F_S)
for i in range(len(boc_sequence)):
remainder += repetitions[i]
j = 0
while(j<math.modf(remainder)[1]):
boc_output.append(boc_sequence[i])
j+=1
remainder = math.modf(remainder)[0]
bit_counter += 1
iqPlot(boc_output, "IQ samples of the BOC(1,1)", len(boc_output)-1)
signal = boc_output * ds_wave_list[:len(boc_output)]
iqPlot(signal, "IQ samples with Doppler Shift", len(signal)-1)
# AWGN simulation
awgn_vector = (np.random.randn(len(signal)) + 1j*np.random.randn(len(signal))) * np.sqrt(N_0/2)
if(pathLossFlag):
# Apply Path Loss
signal = signal * np.sqrt(path_loss_vector[:len(signal)])
iqPlot(signal, "IQ samples with Doppler Shift and Path Loss", len(signal)-1)
if(awgnFlag):
# Apply AWGN
signal = signal + awgn_vector
iqPlot(signal, "IQ samples with Doppler Shift, Path Loss and AWGN", len(signal)-1)
plt.scatter(np.arange(0,len(signal[814000:820000])), np.real(signal[814000:820000]))
plt.title("Real part of the sampled signal\n with Doppler Shift, Path Loss and AWGN")
plt.xlabel("n (sample)")
plt.ylabel("amplitude")
plt.savefig("plots/sampled signal with doppler shift - path loss - awgn.png")
plt.show()
if(writeOutput):
print("\nWriting output...")
# IQ samples writing
for signal_bit in signal:
real_sample = int(quantize_uniform(np.array([np.real(signal_bit)]), -V_SAT, V_SAT,pow(2,BIT_FOR_IQ))[0])
imag_sample = int(quantize_uniform(np.array([np.imag(signal_bit)]), -V_SAT, V_SAT,pow(2,BIT_FOR_IQ))[0])
output_file.write(real_sample.to_bytes(2,byteorder='big',signed=True))
output_file.write(imag_sample.to_bytes(2,byteorder='big',signed=True))
output_file.flush()