Muller & Muller (RRC needed to be implemented...)
This commit is contained in:
183456
QAM/baseband_signal.dat
Normal file
183456
QAM/baseband_signal.dat
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2512
QAM/pll_error.dat
2512
QAM/pll_error.dat
File diff suppressed because it is too large
Load Diff
416
QAM/pll_error1.dat
Normal file
416
QAM/pll_error1.dat
Normal file
@ -0,0 +1,416 @@
|
||||
0 -0.10034777
|
||||
1 -0.07718180
|
||||
2 0.01155289
|
||||
3 0.04739166
|
||||
4 0.01363860
|
||||
5 0.02807331
|
||||
6 -0.03444587
|
||||
7 -0.04817466
|
||||
8 -0.04011746
|
||||
9 -0.15477285
|
||||
10 -0.36801373
|
||||
11 -0.44657056
|
||||
12 -0.42992300
|
||||
13 -0.55858428
|
||||
14 -0.48472017
|
||||
15 -0.28586789
|
||||
16 -0.40340503
|
||||
17 -0.44461907
|
||||
18 -0.37201003
|
||||
19 -0.32577293
|
||||
20 -0.26655383
|
||||
21 -0.28094271
|
||||
22 -0.00061445
|
||||
23 -0.02959035
|
||||
24 -0.01417158
|
||||
25 -0.04066516
|
||||
26 -0.14692443
|
||||
27 -0.36201427
|
||||
28 -0.28155265
|
||||
29 -0.36204217
|
||||
30 -0.42727728
|
||||
31 -0.22367814
|
||||
32 -0.23669835
|
||||
33 -0.19811459
|
||||
34 -0.25376659
|
||||
35 -0.37512988
|
||||
36 -0.54898196
|
||||
37 -0.61755693
|
||||
38 -0.62868933
|
||||
39 -0.82285217
|
||||
40 -0.83342532
|
||||
41 -0.82125744
|
||||
42 -0.85105802
|
||||
43 -0.89447293
|
||||
44 -0.80181095
|
||||
45 -0.75079751
|
||||
46 -0.81717998
|
||||
47 -0.86143867
|
||||
48 -0.89977778
|
||||
49 -0.90524214
|
||||
50 -0.89944907
|
||||
51 -0.94055430
|
||||
52 -1.05859437
|
||||
53 -1.12705360
|
||||
54 -1.21747985
|
||||
55 -1.20417178
|
||||
56 -1.10153147
|
||||
57 -1.06352194
|
||||
58 -0.95951979
|
||||
59 -0.90260925
|
||||
60 -0.79502720
|
||||
61 -0.81839174
|
||||
62 -0.75654452
|
||||
63 -0.65974212
|
||||
64 -0.65939531
|
||||
65 -0.42306460
|
||||
66 -0.41594872
|
||||
67 -0.36266220
|
||||
68 -0.35966069
|
||||
69 -0.28109171
|
||||
70 -0.33120507
|
||||
71 -0.24351916
|
||||
72 -0.31066813
|
||||
73 -0.33731734
|
||||
74 -0.15496259
|
||||
75 -0.21358570
|
||||
76 -0.28858939
|
||||
77 -0.51685915
|
||||
78 -0.39071023
|
||||
79 -0.33499144
|
||||
80 -0.23664529
|
||||
81 -0.11577459
|
||||
82 0.00113636
|
||||
83 0.02837475
|
||||
84 0.26342319
|
||||
85 0.26394013
|
||||
86 0.30173670
|
||||
87 0.27972182
|
||||
88 0.35013453
|
||||
89 0.48408979
|
||||
90 0.54279943
|
||||
91 0.61815850
|
||||
92 0.55482044
|
||||
93 0.67476148
|
||||
94 1.06275501
|
||||
95 0.96406799
|
||||
96 0.91569856
|
||||
97 0.98674658
|
||||
98 0.96811215
|
||||
99 0.99530148
|
||||
100 0.88594019
|
||||
101 0.96434912
|
||||
102 0.94244006
|
||||
103 0.91209874
|
||||
104 0.84369413
|
||||
105 0.76535143
|
||||
106 0.80116051
|
||||
107 0.88273553
|
||||
108 0.81412610
|
||||
109 0.67625016
|
||||
110 0.65484970
|
||||
111 0.77142406
|
||||
112 0.80456294
|
||||
113 0.81303584
|
||||
114 0.77152194
|
||||
115 0.67356386
|
||||
116 0.51613259
|
||||
117 0.50185382
|
||||
118 0.59017355
|
||||
119 0.63793044
|
||||
120 0.71750630
|
||||
121 0.69075222
|
||||
122 0.75002750
|
||||
123 0.92326303
|
||||
124 0.79129112
|
||||
125 0.70186825
|
||||
126 0.66322738
|
||||
127 0.65157063
|
||||
128 0.70583431
|
||||
129 0.70486873
|
||||
130 0.70653227
|
||||
131 0.45065578
|
||||
132 0.53200951
|
||||
133 0.36627955
|
||||
134 0.26711282
|
||||
135 0.21105964
|
||||
136 0.15880057
|
||||
137 0.11905326
|
||||
138 0.21160837
|
||||
139 0.21604215
|
||||
140 0.22855139
|
||||
141 0.15487874
|
||||
142 0.22043965
|
||||
143 0.26988008
|
||||
144 0.29601592
|
||||
145 0.17218337
|
||||
146 0.13868987
|
||||
147 0.08568772
|
||||
148 -0.10043299
|
||||
149 -0.12125407
|
||||
150 -0.13713925
|
||||
151 -0.26603622
|
||||
152 -0.20677414
|
||||
153 -0.14303180
|
||||
154 -0.30079436
|
||||
155 -0.37185403
|
||||
156 -0.53468202
|
||||
157 -0.38468040
|
||||
158 -0.45001185
|
||||
159 -0.61489631
|
||||
160 -0.63441825
|
||||
161 -0.56626299
|
||||
162 -0.70184176
|
||||
163 -0.72035611
|
||||
164 -0.70663248
|
||||
165 -0.65256388
|
||||
166 -0.66688415
|
||||
167 -0.69229990
|
||||
168 -0.66255805
|
||||
169 -0.74399740
|
||||
170 -0.74323749
|
||||
171 -0.90353248
|
||||
172 -0.90025528
|
||||
173 -0.97487892
|
||||
174 -1.02612602
|
||||
175 -0.98011514
|
||||
176 -1.08266332
|
||||
177 -1.00060279
|
||||
178 -1.00501637
|
||||
179 -0.61018678
|
||||
180 -0.56288755
|
||||
181 -0.48072763
|
||||
182 -0.49540527
|
||||
183 -0.28067756
|
||||
184 -0.24485504
|
||||
185 -0.26582185
|
||||
186 -0.24774035
|
||||
187 -0.24192521
|
||||
188 -0.22914256
|
||||
189 -0.11191231
|
||||
190 -0.30318484
|
||||
191 -0.34566418
|
||||
192 -0.37031692
|
||||
193 -0.17305504
|
||||
194 -0.27165698
|
||||
195 -0.16635422
|
||||
196 0.05092695
|
||||
197 0.14605144
|
||||
198 0.02464244
|
||||
199 -0.15289906
|
||||
200 -0.35779592
|
||||
201 -0.28626663
|
||||
202 -0.28205744
|
||||
203 -0.23439235
|
||||
204 -0.20908746
|
||||
205 -0.18469541
|
||||
206 -0.04504949
|
||||
207 -0.24301169
|
||||
208 -0.17353087
|
||||
209 -0.11781022
|
||||
210 -0.01665034
|
||||
211 -0.05459557
|
||||
212 0.05523993
|
||||
213 0.09002261
|
||||
214 0.04877447
|
||||
215 0.21160551
|
||||
216 0.18738382
|
||||
217 0.21894618
|
||||
218 0.27070853
|
||||
219 0.35621988
|
||||
220 0.31809400
|
||||
221 0.29545796
|
||||
222 0.31535103
|
||||
223 -0.00476390
|
||||
224 0.00165342
|
||||
225 0.05029210
|
||||
226 0.09220816
|
||||
227 0.14903885
|
||||
228 0.11349510
|
||||
229 0.11085808
|
||||
230 0.23489696
|
||||
231 0.30923514
|
||||
232 0.21047853
|
||||
233 0.12785947
|
||||
234 0.22865602
|
||||
235 0.32112358
|
||||
236 0.38617709
|
||||
237 0.40897987
|
||||
238 0.55105638
|
||||
239 0.55577072
|
||||
240 0.61867831
|
||||
241 0.69269699
|
||||
242 0.60885864
|
||||
243 0.64963097
|
||||
244 0.63267686
|
||||
245 0.77468285
|
||||
246 0.75111578
|
||||
247 0.65578661
|
||||
248 0.59376696
|
||||
249 0.54957561
|
||||
250 0.49481200
|
||||
251 0.55449539
|
||||
252 0.41921008
|
||||
253 0.40604164
|
||||
254 0.41708967
|
||||
255 0.26035173
|
||||
256 0.19785706
|
||||
257 0.31090987
|
||||
258 0.27002272
|
||||
259 0.22670754
|
||||
260 0.16443728
|
||||
261 0.15402186
|
||||
262 0.08222339
|
||||
263 0.05767921
|
||||
264 0.04344831
|
||||
265 0.24420368
|
||||
266 0.13774306
|
||||
267 0.13501911
|
||||
268 0.11706452
|
||||
269 0.12749295
|
||||
270 0.02260917
|
||||
271 -0.02459630
|
||||
272 0.16166294
|
||||
273 0.04340375
|
||||
274 -0.38923502
|
||||
275 -0.28494860
|
||||
276 -0.24613563
|
||||
277 -0.22030143
|
||||
278 -0.22809171
|
||||
279 -0.15130964
|
||||
280 -0.07439413
|
||||
281 -0.02851236
|
||||
282 -0.02622596
|
||||
283 0.02253917
|
||||
284 0.00015762
|
||||
285 -0.04064354
|
||||
286 -0.00043680
|
||||
287 -0.02564470
|
||||
288 -0.07122785
|
||||
289 -0.17037994
|
||||
290 -0.19687230
|
||||
291 -0.19550743
|
||||
292 -0.24514302
|
||||
293 -0.24510957
|
||||
294 -0.28405968
|
||||
295 -0.28455488
|
||||
296 -0.15964749
|
||||
297 -0.15455640
|
||||
298 -0.30966986
|
||||
299 -0.14300636
|
||||
300 -0.14705574
|
||||
301 -0.29520014
|
||||
302 -0.29976666
|
||||
303 -0.36836000
|
||||
304 -0.48641493
|
||||
305 -0.55904648
|
||||
306 -0.61747475
|
||||
307 -0.79418854
|
||||
308 -0.82793841
|
||||
309 -0.75051339
|
||||
310 -0.66688573
|
||||
311 -0.45010215
|
||||
312 -0.37336172
|
||||
313 -0.29139699
|
||||
314 -0.34600007
|
||||
315 -0.33253444
|
||||
316 -0.36908010
|
||||
317 -0.19842392
|
||||
318 -0.16074198
|
||||
319 -0.20716804
|
||||
320 -0.10257314
|
||||
321 -0.10140779
|
||||
322 0.00765860
|
||||
323 -0.00525619
|
||||
324 0.33423527
|
||||
325 0.34568831
|
||||
326 0.28989856
|
||||
327 0.17627166
|
||||
328 0.30786987
|
||||
329 0.36708101
|
||||
330 0.30052445
|
||||
331 0.14801223
|
||||
332 0.03686918
|
||||
333 -0.00021260
|
||||
334 -0.01222063
|
||||
335 -0.05618842
|
||||
336 -0.19313390
|
||||
337 -0.22007220
|
||||
338 -0.19335751
|
||||
339 -0.18831126
|
||||
340 -0.27722250
|
||||
341 -0.29501470
|
||||
342 -0.30941434
|
||||
343 -0.26857242
|
||||
344 -0.07903230
|
||||
345 -0.11500245
|
||||
346 -0.02061202
|
||||
347 0.15911196
|
||||
348 0.11344833
|
||||
349 0.14587027
|
||||
350 0.07377362
|
||||
351 0.01447603
|
||||
352 -0.04565549
|
||||
353 0.00536406
|
||||
354 0.07211056
|
||||
355 -0.02126635
|
||||
356 -0.16000897
|
||||
357 -0.20999573
|
||||
358 -0.01224748
|
||||
359 0.06818030
|
||||
360 0.07302668
|
||||
361 0.07073088
|
||||
362 0.04115242
|
||||
363 -0.02376698
|
||||
364 0.05558469
|
||||
365 0.02045449
|
||||
366 0.03220122
|
||||
367 0.24047684
|
||||
368 0.22736498
|
||||
369 0.23285135
|
||||
370 0.19520987
|
||||
371 0.18754875
|
||||
372 0.21122488
|
||||
373 0.22781825
|
||||
374 0.16373679
|
||||
375 0.07609624
|
||||
376 0.08943151
|
||||
377 0.05807386
|
||||
378 0.06279659
|
||||
379 0.09377800
|
||||
380 0.07581534
|
||||
381 0.01908165
|
||||
382 0.14951456
|
||||
383 0.32538450
|
||||
384 0.31304640
|
||||
385 0.26282136
|
||||
386 0.26872657
|
||||
387 0.20331544
|
||||
388 0.13513852
|
||||
389 0.09117698
|
||||
390 0.03205175
|
||||
391 0.15207967
|
||||
392 0.17874815
|
||||
393 0.17405716
|
||||
394 0.22438386
|
||||
395 0.25194504
|
||||
396 0.36610595
|
||||
397 0.28387484
|
||||
398 0.36740995
|
||||
399 0.34416235
|
||||
400 0.19153637
|
||||
401 0.31418852
|
||||
402 0.27175776
|
||||
403 0.11585754
|
||||
404 0.09506990
|
||||
405 0.16898167
|
||||
406 0.23997444
|
||||
407 0.24208747
|
||||
408 0.13429443
|
||||
409 0.18641052
|
||||
410 0.19285353
|
||||
411 0.17638997
|
||||
412 0.33073501
|
||||
413 0.55866720
|
||||
414 0.40107339
|
||||
415 0.28855968
|
||||
116
QAM/qam.c
116
QAM/qam.c
@ -363,6 +363,103 @@ void pll(qam_system* qam, double complex* s_with_preamble, double complex* r_cor
|
||||
}
|
||||
}
|
||||
|
||||
// Synchro temporelle Müller et Müller
|
||||
void muller_muller_sync(qam_system* qam, double complex* s_data, int nb_symbols, double Kp_mm, double Ki_mm, double complex* r_mm_out) {
|
||||
double integrator = 0.0;
|
||||
double timing_offset = 0.0;
|
||||
double current_idx_double = 0.0;
|
||||
double complex d_k_minus_1 = 0;
|
||||
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
int opt_idx = (int)round(current_idx_double);
|
||||
|
||||
int tilde_idx = (int)round(current_idx_double + qam->N / 2.0);
|
||||
|
||||
if (opt_idx >= nb_symbols * qam->N || tilde_idx >= nb_symbols * qam->N || tilde_idx < 0)
|
||||
break;
|
||||
|
||||
double complex r_k = s_data[opt_idx];
|
||||
double complex r_tilde_k = s_data[tilde_idx];
|
||||
|
||||
double min_d = INFINITY;
|
||||
double complex d_k = 0;
|
||||
int decision_idx = 0;
|
||||
|
||||
for (int idx = 0; idx < qam->M; idx++) {
|
||||
double d = cabs(r_k - qam->constellation[idx]);
|
||||
if (d < min_d) {
|
||||
min_d = d;
|
||||
d_k = qam->constellation[idx];
|
||||
decision_idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
r_mm_out[k] = r_k;
|
||||
|
||||
// Erreur M&M
|
||||
double error_k = 0.0;
|
||||
if (k > 0) {
|
||||
// Formule M&M: e_k = Re{ r_tilde_k * (d_{k-1}^* - d_k^*) }
|
||||
double complex error_term = r_tilde_k * conj(d_k_minus_1 - d_k);
|
||||
error_k = creal(error_term);
|
||||
}
|
||||
|
||||
// Costas Loop PI
|
||||
integrator += Ki_mm * error_k;
|
||||
timing_offset = Kp_mm * error_k + integrator;
|
||||
|
||||
current_idx_double += qam->N - timing_offset;
|
||||
|
||||
d_k_minus_1 = d_k;
|
||||
}
|
||||
}
|
||||
|
||||
// Demodulation M&M
|
||||
void demodulate_sync_adapted(qam_system* qam, double complex* r_mm_out, int nb_symbols, uint8_t* bits_hat, FILE *fp_constel) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex r = r_mm_out[k];
|
||||
|
||||
if (fp_constel) {
|
||||
fprintf(fp_constel, "% .8f % .8f\n", creal(r), cimag(r));
|
||||
fflush(fp_constel);
|
||||
}
|
||||
|
||||
// Distance euclidien (quantification/décision)
|
||||
double min_d = INFINITY;
|
||||
int i_cl = 0;
|
||||
int j_cl = 0;
|
||||
for (int idx = 0; idx < qam->M; idx++) {
|
||||
double d = cabs(r - qam->constellation[idx]);
|
||||
if (d < min_d) {
|
||||
min_d = d;
|
||||
i_cl = idx / qam->sm;
|
||||
j_cl = idx % qam->sm;
|
||||
}
|
||||
}
|
||||
|
||||
// Gray mapping et extraction des bits
|
||||
if (qam->k % 2 != 0) {
|
||||
printf("demodulate : k doit être pair (k = %d)\n", qam->k);
|
||||
exit(1);
|
||||
}
|
||||
int bits_per_axis = qam->k / 2;
|
||||
|
||||
int i_bin = gray_to_bin(i_cl);
|
||||
int j_bin = gray_to_bin(j_cl);
|
||||
|
||||
for (int b = 0; b < bits_per_axis; b++) {
|
||||
bits_hat[k * qam->k + b] = (i_bin >> (bits_per_axis - 1 - b)) & 1;
|
||||
bits_hat[k * qam->k + bits_per_axis + b] = (j_bin >> (bits_per_axis - 1 - b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void demodulate_carrier(qam_system* qam, double complex* s_input, double complex* s_bandebase, int total_samples) {
|
||||
for (int n = 0; n < total_samples; n++) {
|
||||
double t = (double)n / qam->Fs;
|
||||
s_bandebase[n] = s_input[n] * cexp(-I * 2 * M_PI * qam->Fc * t) / A;
|
||||
}
|
||||
}
|
||||
|
||||
int main () {
|
||||
// Initialisation du system qam
|
||||
@ -377,7 +474,7 @@ int main () {
|
||||
init_constellation(&qam);
|
||||
|
||||
// Conversion du texte en bits
|
||||
char* texte = "Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux";
|
||||
char* texte = "Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux";
|
||||
int nb_chars = strlen(texte);
|
||||
int nb_bits = nb_chars * 8;
|
||||
int nb_symbols = (nb_bits + qam.k - 1) / qam.k;
|
||||
@ -404,7 +501,7 @@ int main () {
|
||||
double complex* s_with_preamble = concat_preamble_signal(preamble_mod, L, s_mod, nb_symbols, qam.N);
|
||||
|
||||
// Ajout du bruit
|
||||
add_noise(s_with_preamble, total_samples, 20);
|
||||
add_noise(s_with_preamble, total_samples, 2);
|
||||
|
||||
FILE *fp_ref = fopen("constellation_ref.dat", "w");
|
||||
fill_constellation_data(&qam, fp_ref);
|
||||
@ -432,22 +529,31 @@ int main () {
|
||||
pll(&qam, s_with_preamble, s_corrected, L, total_samples, nb_symbols, Kp, Ki, alpha, fp_pll_error);
|
||||
fclose(fp_pll_error);
|
||||
|
||||
double complex* s_bande_base = malloc(sizeof(double complex) * nb_symbols * qam.N);
|
||||
demodulate_carrier(&qam, s_corrected + L * qam.N, s_bande_base, total_samples);
|
||||
|
||||
double complex* r_mm_out = malloc(sizeof(double complex) * nb_bits);
|
||||
double Kp_mm = 0.05;
|
||||
double Ki_mm = 0.001;
|
||||
muller_muller_sync(&qam, s_bande_base, nb_symbols, Kp_mm, Ki_mm, r_mm_out);
|
||||
|
||||
// Démodulation
|
||||
FILE *fp_constel = fopen("constellation.dat", "w");
|
||||
uint8_t* output_bits = (uint8_t*)malloc(nb_bits * sizeof(uint8_t));
|
||||
demodulate(&qam, s_corrected + L * qam.N, nb_symbols, output_bits, fp_constel);
|
||||
demodulate_sync_adapted(&qam, r_mm_out, nb_symbols, output_bits, fp_constel);
|
||||
//demodulate(&qam, s_corrected + L * qam.N, nb_symbols, output_bits, fp_constel);
|
||||
fclose(fp_constel);
|
||||
|
||||
// Reconstruction du texte
|
||||
char* texte_recup = malloc(nb_chars + 1);
|
||||
reconstruction_text(nb_chars, output_bits, texte_recup);
|
||||
|
||||
printf("Texte original : %s\n\n", texte);
|
||||
//printf("Texte original : %s\n\n", texte);
|
||||
printf("Texte demodulé : %s\n", texte_recup);
|
||||
|
||||
// Calcul du BER
|
||||
double ber = compare_bits(input_bits, output_bits, nb_bits);
|
||||
printf("Taux d'erreur blind QAM: %.4f\n", ber * 100);
|
||||
printf("Taux d'erreur QAM: %.4f\n", ber * 100);
|
||||
|
||||
// Libération mémoire
|
||||
free(input_bits);
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtWidgets, QtCore
|
||||
import numpy as np
|
||||
import sys, os
|
||||
|
||||
# -------------------- Fichiers de données --------------------
|
||||
REF_FILE = "constellation_ref.dat"
|
||||
RX_FILE = "constellation.dat"
|
||||
ERROR_FILE = "pll_error.dat"
|
||||
|
||||
# -------------------- Fonctions de chargement --------------------
|
||||
def load_points(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
def load_error(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
# -------------------- Application --------------------
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
win = pg.GraphicsLayoutWidget(show=True, title="Constellation")
|
||||
win.resize(900, 900)
|
||||
win.setBackground('#0a0a0a') # fond noir profond
|
||||
|
||||
plot = win.addPlot()
|
||||
plot.setAspectLocked(True) # axes égaux
|
||||
|
||||
# -------------------- Axes stylés --------------------
|
||||
plot.getAxis('left').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('bottom').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('left').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.getAxis('bottom').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.setLabel('left', 'Quadrature (Q)', color='#EEE', size='12pt')
|
||||
plot.setLabel('bottom', 'In-phase (I)', color='#EEE', size='12pt')
|
||||
|
||||
# -------------------- Grille subtile --------------------
|
||||
grid = pg.GridItem()
|
||||
grid.setPen(pg.mkPen('#444', width=1, style=QtCore.Qt.DotLine))
|
||||
plot.addItem(grid)
|
||||
|
||||
# -------------------- Chargement initial --------------------
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
error_data = load_error(ERROR_FILE)
|
||||
|
||||
# Points référence
|
||||
ref_plot = plot.plot(ref_data[:,0], ref_data[:,1],
|
||||
pen=None,
|
||||
symbol='o',
|
||||
symbolSize=10,
|
||||
symbolBrush=pg.mkBrush('#1E90FF'), # bleu vif
|
||||
symbolPen=None,
|
||||
name='Référence')
|
||||
|
||||
# Points reçus
|
||||
rx_plot = plot.plot(rx_data[:,0], rx_data[:,1],
|
||||
pen=None,
|
||||
symbol='x',
|
||||
symbolSize=6,
|
||||
symbolBrush=pg.mkBrush('#FF4500'), # orange vif
|
||||
symbolPen=None,
|
||||
name='Reçu')
|
||||
|
||||
# PLL error en vert
|
||||
error_plot = plot.plot(error_data[:,0], error_data[:,1],
|
||||
pen=pg.mkPen('#00FF00', width=2),
|
||||
symbol=None,
|
||||
name='PLL error')
|
||||
|
||||
# -------------------- Légende stylée --------------------
|
||||
legend = plot.addLegend()
|
||||
for item in legend.items:
|
||||
item[1].setPen(pg.mkPen('#FFF', width=2))
|
||||
|
||||
# -------------------- Timer pour mise à jour dynamique --------------------
|
||||
def update():
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
error_data = load_error(ERROR_FILE)
|
||||
|
||||
if ref_data.size > 0:
|
||||
ref_plot.setData(ref_data[:,0], ref_data[:,1])
|
||||
if rx_data.size > 0:
|
||||
rx_plot.setData(rx_data[:,0], rx_data[:,1])
|
||||
if error_data.size > 0:
|
||||
error_plot.setData(error_data[:,0], error_data[:,1])
|
||||
|
||||
timer = QtCore.QTimer()
|
||||
timer.timeout.connect(update)
|
||||
timer.start(500) # ms
|
||||
|
||||
# -------------------- Anti-aliasing --------------------
|
||||
pg.setConfigOptions(antialias=True)
|
||||
|
||||
# -------------------- Exécution --------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(app.exec_())
|
||||
|
||||
250
QAM/save/1/qam.c
250
QAM/save/1/qam.c
@ -1,250 +0,0 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <complex.h>
|
||||
#include <string.h>
|
||||
|
||||
#define A 10
|
||||
|
||||
struct qam_system_s {
|
||||
int M; // Nombre de symboles M-QAM
|
||||
int k; // Nombre de bits/symboles
|
||||
double Fs; // Fréquence d'échantillionage
|
||||
double Ts; // Temps d'échantillionage
|
||||
int N; // Nombre d'échantillions
|
||||
double Fc; // Fréquence de la porteuse
|
||||
double complex** constellation; // Tableau de symboles I + j Q
|
||||
};
|
||||
typedef struct qam_system_s qam_system;
|
||||
|
||||
// Initialisation de la constellation (double tableau de taille sqrt(M)),
|
||||
// ToDo : changer à un tableau à 1 dimension pour éviter de calculer sqrt(M)
|
||||
void init_constellation (qam_system* qam) {
|
||||
int sm = (int)sqrt(qam->M);
|
||||
qam->constellation = (double complex**)malloc(sizeof(double complex*) * sm);
|
||||
|
||||
for (int i = 0; i < sm; i++) {
|
||||
qam->constellation[i] = (double complex*)malloc(sizeof(double complex) * sm);
|
||||
}
|
||||
|
||||
double norm_factor = sqrt((double)(qam->M - 1) / 3.0); // Pour puissance unitaire
|
||||
|
||||
for (int i = 0; i < sm; i++) {
|
||||
double complex ip = -(sm - 1) + 2 * i;
|
||||
for (int j = 0; j < sm; j++) {
|
||||
double complex qp = -(sm - 1) + 2 * j;
|
||||
qam->constellation[i][j] = (ip + I * qp) / norm_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modulation QAM
|
||||
void modulate (qam_system* qam, double complex* symbols, int nb_symbols, double complex* s) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex iq = symbols[k];
|
||||
for (int n = 0; n < qam->N; n++) {
|
||||
int idx = k * qam->N + n;
|
||||
s[idx] = A * iq * cexp(2 * I * M_PI * qam->Fc * ((double)idx / qam->Fs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Demodulation QAM
|
||||
void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat, FILE *fp_constel) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex r = 0;
|
||||
for (int n = 0; n < qam->N; n++) {
|
||||
r += s[k * qam->N + n] * cexp(-2 * I * M_PI * qam->Fc * ((double)(k * qam->N + n) / qam->Fs)) / A;
|
||||
}
|
||||
r /= qam->N;
|
||||
|
||||
if (fp_constel) {
|
||||
fprintf(fp_constel, "% .8f % .8f\n", creal(r), cimag(r));
|
||||
fflush(fp_constel);
|
||||
}
|
||||
|
||||
// Distance euclidien de Ir et Qr pour avoir le point le plus proche de la constellation (lent)
|
||||
int sm = (int)sqrt(qam->M);
|
||||
double min_d = INFINITY;
|
||||
int i_cl = 0;
|
||||
int j_cl = 0;
|
||||
for (int i = 0; i < sm; i++) {
|
||||
for (int j = 0; j < sm; j++) {
|
||||
double d = cabs(r - qam->constellation[i][j]);
|
||||
if (d < min_d) {
|
||||
min_d = d;
|
||||
i_cl = i;
|
||||
j_cl = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// index du symbole (id) : même mappage que dans bits_to_symbols()
|
||||
int id = i_cl * sm + j_cl;
|
||||
|
||||
for (int b = 0; b < qam->k; b++) {
|
||||
bits_hat[k * qam->k + b] = (id >> (qam->k - 1 - b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calcul du bruit gaussien pour un sigma donné
|
||||
// Formule de Box-Muller
|
||||
double gaussian_noise (double sigma) {
|
||||
double u1 = (rand() + 1) / ((double)RAND_MAX + 2);
|
||||
double u2 = (rand() + 1) / ((double)RAND_MAX + 2);
|
||||
return sigma * sqrt(-2 * log(u1)) * cos(2 * M_PI * u2);
|
||||
}
|
||||
|
||||
// Ajout du bruit
|
||||
void add_noise (double complex* s, int len, double sigma) {
|
||||
//double signal_power = (2.0/3.0)*(qam.M-1);
|
||||
//double snr_dB = 5; // SNR en dB
|
||||
//double snr_lin = pow(10.0, snr_dB / 10.0);
|
||||
//double sigma = sqrt(signal_power / snr_lin);
|
||||
for (int i = 0; i < len; i++) {
|
||||
double nr = gaussian_noise(sigma);
|
||||
double ni = gaussian_noise(sigma);
|
||||
s[i] += nr + I * ni;
|
||||
}
|
||||
}
|
||||
|
||||
// Changer le tableau de bits en boolen ou alors la represenation binaire et shifter pour extraire les bits (pas bien si M plus grand)
|
||||
void bits_to_symbols (qam_system* qam, uint8_t* bits, int nb_bits, double complex* symbols) {
|
||||
int nb_symbols = nb_bits / qam->k;
|
||||
int sm = sqrt(qam->M);
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
int id = 0;
|
||||
for (int b = 0 ; b < qam->k; b++) {
|
||||
id = id * 2 + bits[k * qam->k + b];
|
||||
}
|
||||
int i = id / sm;
|
||||
int j = id % sm;
|
||||
symbols[k] = qam->constellation[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
double compare_bits(uint8_t* bits1, uint8_t* bits2, int nb_bits) {
|
||||
int errors = 0;
|
||||
for (int i = 0; i < nb_bits; i++) {
|
||||
if (bits1[i] != bits2[i]) errors++;
|
||||
}
|
||||
return (double)errors / nb_bits;
|
||||
}
|
||||
|
||||
void add_dephasage(double complex* s, double phi_offset, int total_samples) {
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
s[i] *= cexp(I * phi_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void add_freq(qam_system* qam, double complex* s, double freq_offset, int total_samples) {
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
double t = (double)i / qam->Fs;
|
||||
s[i] *= cexp(I * 2 * M_PI * freq_offset * t);
|
||||
}
|
||||
}
|
||||
|
||||
void fill_constellation_data(qam_system* qam, FILE *fp_ref) {
|
||||
int sm = (int)sqrt(qam->M);
|
||||
for (int i = 0; i < sm; i++) {
|
||||
for (int j = 0; j < sm; j++) {
|
||||
fprintf(fp_ref, "% .8f % .8f\n", creal(qam->constellation[i][j]), cimag(qam->constellation[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reconstruction_text(int nb_chars, uint8_t* output_bits, char* texte_recup) {
|
||||
for(int i = 0; i < nb_chars; i++){
|
||||
char c = 0;
|
||||
for(int b = 0; b < 8; b++){
|
||||
c |= output_bits[i*8 + b] << (7-b);
|
||||
}
|
||||
texte_recup[i] = c;
|
||||
}
|
||||
texte_recup[nb_chars] = '\0';
|
||||
}
|
||||
|
||||
void conversion_text_to_bits(int nb_chars, int nb_bits, char* texte, uint8_t* input_bits) {
|
||||
for(int i = 0; i < nb_chars; i++){
|
||||
for(int b = 0; b < 8; b++){
|
||||
input_bits[i*8 + b] = (texte[i] >> (7-b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Libération de la mémoire
|
||||
void free_constellation(qam_system* qam) {
|
||||
int sm = (int)sqrt(qam->M);
|
||||
for (int i = 0; i < sm; i++)
|
||||
free(qam->constellation[i]);
|
||||
free(qam->constellation);
|
||||
}
|
||||
|
||||
int main () {
|
||||
qam_system qam;
|
||||
qam.M = 16;
|
||||
qam.k = (int)log2((double)(qam.M));
|
||||
qam.Fs = 44100;
|
||||
qam.Ts = 0.01;
|
||||
qam.N = (int)(qam.Fs * qam.Ts);
|
||||
qam.Fc = 2000;
|
||||
init_constellation(&qam);
|
||||
|
||||
// Conversion du texte en bits
|
||||
char* texte = "Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux";
|
||||
int nb_chars = strlen(texte);
|
||||
int nb_bits = nb_chars * 8;
|
||||
int nb_symbols = (nb_bits + qam.k - 1) / qam.k;
|
||||
uint8_t* input_bits = malloc(nb_bits * sizeof(uint8_t));
|
||||
conversion_text_to_bits(nb_chars, nb_bits, texte, input_bits);
|
||||
|
||||
// Conversion en symboles
|
||||
double complex* symbols = malloc(sizeof(double complex) * nb_symbols);
|
||||
bits_to_symbols(&qam, input_bits, nb_bits, symbols);
|
||||
|
||||
// Modulation
|
||||
int total_samples = qam.N * nb_symbols;
|
||||
double complex* s = malloc(sizeof(double complex) * total_samples);
|
||||
modulate(&qam, symbols, nb_symbols, s);
|
||||
|
||||
// Ajout du bruit
|
||||
add_noise(s, total_samples, 120);
|
||||
|
||||
FILE *fp_ref = fopen("constellation_ref.dat", "w");
|
||||
fill_constellation_data(&qam, fp_ref);
|
||||
fclose(fp_ref);
|
||||
|
||||
// Ajout de dephasage
|
||||
//add_dephasage(s, M_PI / 6.0, total_samples);
|
||||
|
||||
// AJout de decalage de fréquence
|
||||
//add_freq(&qam, s, 1, total_samples);
|
||||
|
||||
// Démodulation
|
||||
FILE *fp_constel = fopen("constellation.dat", "w");
|
||||
uint8_t* output_bits = (uint8_t*)malloc(nb_bits * sizeof(uint8_t));
|
||||
demodulate(&qam, s, nb_symbols, output_bits, fp_constel);
|
||||
fclose(fp_constel);
|
||||
|
||||
// Reconstruction du texte
|
||||
char* texte_recup = malloc(nb_chars + 1);
|
||||
reconstruction_text(nb_chars, output_bits, texte_recup);
|
||||
|
||||
printf("Texte original : %s\n\n", texte);
|
||||
printf("Texte demodulé : %s\n", texte_recup);
|
||||
|
||||
// Calcul du BER
|
||||
double ber = compare_bits(input_bits, output_bits, nb_bits);
|
||||
printf("Taux d'erreur blind QAM: %.4f\n", ber * 100);
|
||||
|
||||
// Libération mémoire
|
||||
free(input_bits);
|
||||
free(output_bits);
|
||||
free(symbols);
|
||||
free(s);
|
||||
free_constellation(&qam);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,104 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtWidgets, QtCore
|
||||
import numpy as np
|
||||
import sys, os
|
||||
|
||||
# -------------------- Fichiers de données --------------------
|
||||
REF_FILE = "constellation_ref.dat"
|
||||
RX_FILE = "constellation.dat"
|
||||
ERROR_FILE = "pll_error.dat"
|
||||
|
||||
# -------------------- Fonctions de chargement --------------------
|
||||
def load_points(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
def load_error(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
# -------------------- Application --------------------
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
win = pg.GraphicsLayoutWidget(show=True, title="Constellation")
|
||||
win.resize(900, 900)
|
||||
win.setBackground('#0a0a0a') # fond noir profond
|
||||
|
||||
plot = win.addPlot()
|
||||
plot.setAspectLocked(True) # axes égaux
|
||||
|
||||
# -------------------- Axes stylés --------------------
|
||||
plot.getAxis('left').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('bottom').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('left').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.getAxis('bottom').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.setLabel('left', 'Quadrature (Q)', color='#EEE', size='12pt')
|
||||
plot.setLabel('bottom', 'In-phase (I)', color='#EEE', size='12pt')
|
||||
|
||||
# -------------------- Grille subtile --------------------
|
||||
grid = pg.GridItem()
|
||||
grid.setPen(pg.mkPen('#444', width=1, style=QtCore.Qt.DotLine))
|
||||
plot.addItem(grid)
|
||||
|
||||
# -------------------- Chargement initial --------------------
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
error_data = load_error(ERROR_FILE)
|
||||
|
||||
# Points référence
|
||||
ref_plot = plot.plot(ref_data[:,0], ref_data[:,1],
|
||||
pen=None,
|
||||
symbol='o',
|
||||
symbolSize=10,
|
||||
symbolBrush=pg.mkBrush('#1E90FF'), # bleu vif
|
||||
symbolPen=None,
|
||||
name='Référence')
|
||||
|
||||
# Points reçus
|
||||
rx_plot = plot.plot(rx_data[:,0], rx_data[:,1],
|
||||
pen=None,
|
||||
symbol='x',
|
||||
symbolSize=6,
|
||||
symbolBrush=pg.mkBrush('#FF4500'), # orange vif
|
||||
symbolPen=None,
|
||||
name='Reçu')
|
||||
|
||||
# PLL error en vert
|
||||
error_plot = plot.plot(error_data[:,0], error_data[:,1],
|
||||
pen=pg.mkPen('#00FF00', width=2),
|
||||
symbol=None,
|
||||
name='PLL error')
|
||||
|
||||
# -------------------- Légende stylée --------------------
|
||||
legend = plot.addLegend()
|
||||
for item in legend.items:
|
||||
item[1].setPen(pg.mkPen('#FFF', width=2))
|
||||
|
||||
# -------------------- Timer pour mise à jour dynamique --------------------
|
||||
def update():
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
error_data = load_error(ERROR_FILE)
|
||||
|
||||
if ref_data.size > 0:
|
||||
ref_plot.setData(ref_data[:,0], ref_data[:,1])
|
||||
if rx_data.size > 0:
|
||||
rx_plot.setData(rx_data[:,0], rx_data[:,1])
|
||||
if error_data.size > 0:
|
||||
error_plot.setData(error_data[:,0], error_data[:,1])
|
||||
|
||||
timer = QtCore.QTimer()
|
||||
timer.timeout.connect(update)
|
||||
timer.start(500) # ms
|
||||
|
||||
# -------------------- Anti-aliasing --------------------
|
||||
pg.setConfigOptions(antialias=True)
|
||||
|
||||
# -------------------- Exécution --------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(app.exec_())
|
||||
|
||||
312
QAM/save/2/qam.c
312
QAM/save/2/qam.c
@ -1,312 +0,0 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <complex.h>
|
||||
#include <string.h>
|
||||
|
||||
#define A 10
|
||||
|
||||
struct qam_system_s {
|
||||
int M; // Nombre de symboles M-QAM
|
||||
int k; // Nombre de bits/symboles
|
||||
double Fs; // Fréquence d'échantillionage
|
||||
double Ts; // Temps d'échantillionage
|
||||
int N; // Nombre d'échantillions
|
||||
double Fc; // Fréquence de la porteuse
|
||||
double complex** constellation; // Tableau de symboles I + j Q
|
||||
};
|
||||
typedef struct qam_system_s qam_system;
|
||||
|
||||
// Initialisation de la constellation (double tableau de taille sqrt(M)),
|
||||
// ToDo : changer à un tableau à 1 dimension pour éviter de calculer sqrt(M)
|
||||
void init_constellation (qam_system* qam) {
|
||||
int sm = (int)sqrt(qam->M);
|
||||
qam->constellation = (double complex**)malloc(sizeof(double complex*) * sm);
|
||||
|
||||
for (int i = 0; i < sm; i++) {
|
||||
qam->constellation[i] = (double complex*)malloc(sizeof(double complex) * sm);
|
||||
}
|
||||
|
||||
double norm_factor = sqrt((double)(qam->M - 1) / 3.0); // Pour puissance unitaire
|
||||
|
||||
for (int i = 0; i < sm; i++) {
|
||||
double complex ip = -(sm - 1) + 2 * i;
|
||||
for (int j = 0; j < sm; j++) {
|
||||
double complex qp = -(sm - 1) + 2 * j;
|
||||
qam->constellation[i][j] = (ip + I * qp) / norm_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bin_to_gray (int x) {
|
||||
return x ^ (x >> 1);
|
||||
}
|
||||
|
||||
// Iteration de XOR
|
||||
int gray_to_bin(int g) {
|
||||
int b = g;
|
||||
while (g >>= 1)
|
||||
b ^= g;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Modulation QAM
|
||||
void modulate (qam_system* qam, double complex* symbols, int nb_symbols, double complex* s) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex iq = symbols[k];
|
||||
for (int n = 0; n < qam->N; n++) {
|
||||
int idx = k * qam->N + n;
|
||||
s[idx] = A * iq * cexp(2 * I * M_PI * qam->Fc * ((double)idx / qam->Fs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Demodulation QAM
|
||||
void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat, FILE *fp_constel) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex r = 0;
|
||||
for (int n = 0; n < qam->N; n++) {
|
||||
r += s[k * qam->N + n] * cexp(-2 * I * M_PI * qam->Fc * ((double)(k * qam->N + n) / qam->Fs)) / A;
|
||||
}
|
||||
r /= qam->N;
|
||||
|
||||
if (fp_constel) {
|
||||
fprintf(fp_constel, "% .8f % .8f\n", creal(r), cimag(r));
|
||||
fflush(fp_constel);
|
||||
}
|
||||
|
||||
// Distance euclidien de Ir et Qr pour avoir le point le plus proche de la constellation (lent)
|
||||
int sm = (int)sqrt(qam->M);
|
||||
double min_d = INFINITY;
|
||||
int i_cl = 0;
|
||||
int j_cl = 0;
|
||||
for (int i = 0; i < sm; i++) {
|
||||
for (int j = 0; j < sm; j++) {
|
||||
double d = cabs(r - qam->constellation[i][j]);
|
||||
if (d < min_d) {
|
||||
min_d = d;
|
||||
i_cl = i;
|
||||
j_cl = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Ancienne methode (non gray)
|
||||
// index du symbole (id) : même mappage que dans bits_to_symbols()
|
||||
int id = i_cl * sm + j_cl;
|
||||
|
||||
for (int b = 0; b < qam->k; b++) {
|
||||
bits_hat[k * qam->k + b] = (id >> (qam->k - 1 - b)) & 1;
|
||||
}
|
||||
*/
|
||||
|
||||
// Gray mapping
|
||||
if (qam->k % 2 != 0) {
|
||||
printf("demodulate : k pair (k = %d)\n", qam->k);
|
||||
exit(1);
|
||||
}
|
||||
int bits_per_axis = qam->k / 2;
|
||||
|
||||
int i_bin = gray_to_bin(i_cl);
|
||||
int j_bin = gray_to_bin(j_cl);
|
||||
|
||||
for (int b = 0; b < bits_per_axis; b++) {
|
||||
bits_hat[k * qam->k + b] = (i_bin >> (bits_per_axis - 1 - b)) & 1;
|
||||
bits_hat[k * qam->k + bits_per_axis + b] = (j_bin >> (bits_per_axis - 1 - b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calcul du bruit gaussien pour un sigma donné
|
||||
// Formule de Box-Muller
|
||||
double gaussian_noise (double sigma) {
|
||||
double u1 = (rand() + 1) / ((double)RAND_MAX + 2);
|
||||
double u2 = (rand() + 1) / ((double)RAND_MAX + 2);
|
||||
return sigma * sqrt(-2 * log(u1)) * cos(2 * M_PI * u2);
|
||||
}
|
||||
|
||||
// Ajout du bruit
|
||||
void add_noise (double complex* s, int len, double sigma) {
|
||||
//double signal_power = (2.0/3.0)*(qam.M-1);
|
||||
//double snr_dB = 5; // SNR en dB
|
||||
//double snr_lin = pow(10.0, snr_dB / 10.0);
|
||||
//double sigma = sqrt(signal_power / snr_lin);
|
||||
for (int i = 0; i < len; i++) {
|
||||
double nr = gaussian_noise(sigma);
|
||||
double ni = gaussian_noise(sigma);
|
||||
s[i] += nr + I * ni;
|
||||
}
|
||||
}
|
||||
|
||||
// Changer le tableau de bits en boolen ou alors la represenation binaire et shifter pour extraire les bits (pas bien si M plus grand)
|
||||
/*void bits_to_symbols (qam_system* qam, uint8_t* bits, int nb_bits, double complex* symbols) {
|
||||
int nb_symbols = nb_bits / qam->k;
|
||||
int sm = sqrt(qam->M);
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
int id = 0;
|
||||
for (int b = 0 ; b < qam->k; b++) {
|
||||
id = id * 2 + bits[k * qam->k + b];
|
||||
}
|
||||
int i = id / sm;
|
||||
int j = id % sm;
|
||||
symbols[k] = qam->constellation[i][j];
|
||||
}
|
||||
}*/
|
||||
|
||||
void bits_to_symbols (qam_system* qam, uint8_t* bits, int nb_bits, double complex* symbols) {
|
||||
int nb_symbols = nb_bits / qam->k;
|
||||
int sm = (int)sqrt(qam->M);
|
||||
|
||||
// k pair
|
||||
if (qam->k % 2 != 0) {
|
||||
printf("bits_to_symbols : k doit être pair (k = %d) \n", qam->k);
|
||||
exit(1);
|
||||
}
|
||||
int bits_per_axis = qam->k / 2;
|
||||
|
||||
for (int sym = 0; sym < nb_symbols; sym++) {
|
||||
// Construire les indices binaires i_bin (MSB...) et j_bin (LSB...)
|
||||
int i_bin = 0;
|
||||
int j_bin = 0;
|
||||
for (int b = 0; b < bits_per_axis; b++) {
|
||||
i_bin = (i_bin << 1) | bits[sym * qam->k + b];
|
||||
j_bin = (j_bin << 1) | bits[sym * qam->k + bits_per_axis + b];
|
||||
}
|
||||
|
||||
int i_gray = bin_to_gray(i_bin);
|
||||
int j_gray = bin_to_gray(j_bin);
|
||||
|
||||
if (i_gray < 0 || i_gray >= sm || j_gray < 0 || j_gray >= sm) {
|
||||
printf("bits_to_symbols : IOOR i_gray = %d j_gray = %d sm = %d \n", i_gray, j_gray, sm);
|
||||
exit(1);
|
||||
}
|
||||
symbols[sym] = qam->constellation[i_gray][j_gray];
|
||||
}
|
||||
}
|
||||
|
||||
double compare_bits(uint8_t* bits1, uint8_t* bits2, int nb_bits) {
|
||||
int errors = 0;
|
||||
for (int i = 0; i < nb_bits; i++) {
|
||||
if (bits1[i] != bits2[i]) errors++;
|
||||
}
|
||||
return (double)errors / nb_bits;
|
||||
}
|
||||
|
||||
void add_dephasage(double complex* s, double phi_offset, int total_samples) {
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
s[i] *= cexp(I * phi_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void add_freq(qam_system* qam, double complex* s, double freq_offset, int total_samples) {
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
double t = (double)i / qam->Fs;
|
||||
s[i] *= cexp(I * 2 * M_PI * freq_offset * t);
|
||||
}
|
||||
}
|
||||
|
||||
void fill_constellation_data(qam_system* qam, FILE *fp_ref) {
|
||||
int sm = (int)sqrt(qam->M);
|
||||
for (int i = 0; i < sm; i++) {
|
||||
for (int j = 0; j < sm; j++) {
|
||||
fprintf(fp_ref, "% .8f % .8f\n", creal(qam->constellation[i][j]), cimag(qam->constellation[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reconstruction_text(int nb_chars, uint8_t* output_bits, char* texte_recup) {
|
||||
for(int i = 0; i < nb_chars; i++){
|
||||
char c = 0;
|
||||
for(int b = 0; b < 8; b++){
|
||||
c |= output_bits[i*8 + b] << (7-b);
|
||||
}
|
||||
texte_recup[i] = c;
|
||||
}
|
||||
texte_recup[nb_chars] = '\0';
|
||||
}
|
||||
|
||||
void text_to_bits(int nb_chars, int nb_bits, char* texte, uint8_t* input_bits) {
|
||||
for(int i = 0; i < nb_chars; i++){
|
||||
for(int b = 0; b < 8; b++){
|
||||
input_bits[i*8 + b] = (texte[i] >> (7-b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Libération de la mémoire
|
||||
void free_constellation(qam_system* qam) {
|
||||
int sm = (int)sqrt(qam->M);
|
||||
for (int i = 0; i < sm; i++)
|
||||
free(qam->constellation[i]);
|
||||
free(qam->constellation);
|
||||
}
|
||||
|
||||
int main () {
|
||||
// Initialisation du system qam
|
||||
qam_system qam;
|
||||
qam.M = 16;
|
||||
qam.k = (int)log2((double)(qam.M));
|
||||
qam.Fs = 44100;
|
||||
qam.Ts = 0.01;
|
||||
qam.N = (int)(qam.Fs * qam.Ts);
|
||||
qam.Fc = 2000;
|
||||
init_constellation(&qam);
|
||||
|
||||
// Conversion du texte en bits
|
||||
char* texte = "Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux";
|
||||
int nb_chars = strlen(texte);
|
||||
int nb_bits = nb_chars * 8;
|
||||
int nb_symbols = (nb_bits + qam.k - 1) / qam.k;
|
||||
uint8_t* input_bits = malloc(nb_bits * sizeof(uint8_t));
|
||||
text_to_bits(nb_chars, nb_bits, texte, input_bits);
|
||||
|
||||
// Conversion en symboles
|
||||
double complex* symbols = malloc(sizeof(double complex) * nb_symbols);
|
||||
bits_to_symbols(&qam, input_bits, nb_bits, symbols);
|
||||
|
||||
// Modulation
|
||||
int total_samples = qam.N * nb_symbols;
|
||||
double complex* s = malloc(sizeof(double complex) * total_samples);
|
||||
modulate(&qam, symbols, nb_symbols, s);
|
||||
|
||||
// Ajout du bruit
|
||||
add_noise(s, total_samples, 0);
|
||||
|
||||
FILE *fp_ref = fopen("constellation_ref.dat", "w");
|
||||
fill_constellation_data(&qam, fp_ref);
|
||||
fclose(fp_ref);
|
||||
|
||||
// Ajout de dephasage
|
||||
//add_dephasage(s, M_PI / 6.0, total_samples);
|
||||
|
||||
// AJout de decalage de fréquence
|
||||
//add_freq(&qam, s, 1, total_samples);
|
||||
|
||||
// Démodulation
|
||||
FILE *fp_constel = fopen("constellation.dat", "w");
|
||||
uint8_t* output_bits = (uint8_t*)malloc(nb_bits * sizeof(uint8_t));
|
||||
demodulate(&qam, s, nb_symbols, output_bits, fp_constel);
|
||||
fclose(fp_constel);
|
||||
|
||||
// Reconstruction du texte
|
||||
char* texte_recup = malloc(nb_chars + 1);
|
||||
reconstruction_text(nb_chars, output_bits, texte_recup);
|
||||
|
||||
printf("Texte original : %s\n\n", texte);
|
||||
printf("Texte demodulé : %s\n", texte_recup);
|
||||
|
||||
// Calcul du BER
|
||||
double ber = compare_bits(input_bits, output_bits, nb_bits);
|
||||
printf("Taux d'erreur blind QAM: %.4f\n", ber * 100);
|
||||
|
||||
// Libération mémoire
|
||||
free(input_bits);
|
||||
free(output_bits);
|
||||
free(symbols);
|
||||
free(s);
|
||||
free_constellation(&qam);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,104 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.Qt import QtWidgets, QtCore
|
||||
import numpy as np
|
||||
import sys, os
|
||||
|
||||
# -------------------- Fichiers de données --------------------
|
||||
REF_FILE = "constellation_ref.dat"
|
||||
RX_FILE = "constellation.dat"
|
||||
ERROR_FILE = "pll_error.dat"
|
||||
|
||||
# -------------------- Fonctions de chargement --------------------
|
||||
def load_points(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
def load_error(filename):
|
||||
if os.path.exists(filename):
|
||||
return np.loadtxt(filename)
|
||||
else:
|
||||
return np.zeros((0,2))
|
||||
|
||||
# -------------------- Application --------------------
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
win = pg.GraphicsLayoutWidget(show=True, title="Constellation")
|
||||
win.resize(900, 900)
|
||||
win.setBackground('#0a0a0a') # fond noir profond
|
||||
|
||||
plot = win.addPlot()
|
||||
plot.setAspectLocked(True) # axes égaux
|
||||
|
||||
# -------------------- Axes stylés --------------------
|
||||
plot.getAxis('left').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('bottom').setPen(pg.mkPen('#AAA', width=2))
|
||||
plot.getAxis('left').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.getAxis('bottom').setTextPen(pg.mkPen('#EEE'))
|
||||
plot.setLabel('left', 'Quadrature (Q)', color='#EEE', size='12pt')
|
||||
plot.setLabel('bottom', 'In-phase (I)', color='#EEE', size='12pt')
|
||||
|
||||
# -------------------- Grille subtile --------------------
|
||||
grid = pg.GridItem()
|
||||
grid.setPen(pg.mkPen('#444', width=1, style=QtCore.Qt.DotLine))
|
||||
plot.addItem(grid)
|
||||
|
||||
# -------------------- Chargement initial --------------------
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
error_data = load_error(ERROR_FILE)
|
||||
|
||||
# Points référence
|
||||
ref_plot = plot.plot(ref_data[:,0], ref_data[:,1],
|
||||
pen=None,
|
||||
symbol='o',
|
||||
symbolSize=10,
|
||||
symbolBrush=pg.mkBrush('#1E90FF'), # bleu vif
|
||||
symbolPen=None,
|
||||
name='Référence')
|
||||
|
||||
# Points reçus
|
||||
rx_plot = plot.plot(rx_data[:,0], rx_data[:,1],
|
||||
pen=None,
|
||||
symbol='x',
|
||||
symbolSize=6,
|
||||
symbolBrush=pg.mkBrush('#FF4500'), # orange vif
|
||||
symbolPen=None,
|
||||
name='Reçu')
|
||||
|
||||
# PLL error en vert
|
||||
error_plot = plot.plot(error_data[:,0], error_data[:,1],
|
||||
pen=pg.mkPen('#00FF00', width=2),
|
||||
symbol=None,
|
||||
name='PLL error')
|
||||
|
||||
# -------------------- Légende stylée --------------------
|
||||
legend = plot.addLegend()
|
||||
for item in legend.items:
|
||||
item[1].setPen(pg.mkPen('#FFF', width=2))
|
||||
|
||||
# -------------------- Timer pour mise à jour dynamique --------------------
|
||||
def update():
|
||||
ref_data = load_points(REF_FILE)
|
||||
rx_data = load_points(RX_FILE)
|
||||
error_data = load_error(ERROR_FILE)
|
||||
|
||||
if ref_data.size > 0:
|
||||
ref_plot.setData(ref_data[:,0], ref_data[:,1])
|
||||
if rx_data.size > 0:
|
||||
rx_plot.setData(rx_data[:,0], rx_data[:,1])
|
||||
if error_data.size > 0:
|
||||
error_plot.setData(error_data[:,0], error_data[:,1])
|
||||
|
||||
timer = QtCore.QTimer()
|
||||
timer.timeout.connect(update)
|
||||
timer.start(500) # ms
|
||||
|
||||
# -------------------- Anti-aliasing --------------------
|
||||
pg.setConfigOptions(antialias=True)
|
||||
|
||||
# -------------------- Exécution --------------------
|
||||
if __name__ == '__main__':
|
||||
sys.exit(app.exec_())
|
||||
|
||||
278
QAM/save/3/qam.c
278
QAM/save/3/qam.c
@ -1,278 +0,0 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <complex.h>
|
||||
#include <string.h>
|
||||
|
||||
#define A 10
|
||||
|
||||
struct qam_system_s {
|
||||
int M; // Nombre de symboles M-QAM
|
||||
int k; // Nombre de bits/symboles
|
||||
int sm; // sqrt M
|
||||
double Fs; // Fréquence d'échantillionage
|
||||
double Ts; // Temps d'échantillionage
|
||||
int N; // Nombre d'échantillions
|
||||
double Fc; // Fréquence de la porteuse
|
||||
double complex* constellation; // Tableau de symboles I + j Q 1D
|
||||
};
|
||||
typedef struct qam_system_s qam_system;
|
||||
|
||||
// Initialisation de la constellation (double tableau de taille sqrt(M)),
|
||||
void init_constellation (qam_system* qam) {
|
||||
qam->constellation = (double complex*)malloc(sizeof(double complex) * qam->M);
|
||||
|
||||
double norm_factor = sqrt((double)(qam->M - 1) / 3.0); // Pour puissance unitaire
|
||||
|
||||
for (int i = 0; i < qam->sm; i++) {
|
||||
double ip = -(qam->sm - 1) + 2 * i;
|
||||
for (int j = 0; j < qam->sm; j++) {
|
||||
double qp = -(qam->sm - 1) + 2 * j;
|
||||
int idx = i * qam->sm + j;
|
||||
qam->constellation[idx] = (ip + I * qp) / norm_factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bin_to_gray (int x) {
|
||||
return x ^ (x >> 1);
|
||||
}
|
||||
|
||||
// Iteration de XOR
|
||||
int gray_to_bin(int g) {
|
||||
int b = g;
|
||||
while (g >>= 1)
|
||||
b ^= g;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Modulation QAM
|
||||
void modulate (qam_system* qam, double complex* symbols, int nb_symbols, double complex* s) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex iq = symbols[k];
|
||||
for (int n = 0; n < qam->N; n++) {
|
||||
int idx = k * qam->N + n;
|
||||
s[idx] = A * iq * cexp(2 * I * M_PI * qam->Fc * ((double)idx / qam->Fs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Demodulation QAM
|
||||
void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat, FILE *fp_constel) {
|
||||
for (int k = 0; k < nb_symbols; k++) {
|
||||
double complex r = 0;
|
||||
for (int n = 0; n < qam->N; n++) {
|
||||
r += s[k * qam->N + n] * cexp(-2 * I * M_PI * qam->Fc * ((double)(k * qam->N + n) / qam->Fs)) / A;
|
||||
}
|
||||
r /= qam->N;
|
||||
|
||||
if (fp_constel) {
|
||||
fprintf(fp_constel, "% .8f % .8f\n", creal(r), cimag(r));
|
||||
fflush(fp_constel);
|
||||
}
|
||||
|
||||
// Distance euclidien de Ir et Qr pour avoir le point le plus proche de la constellation (lent)
|
||||
double min_d = INFINITY;
|
||||
int i_cl = 0;
|
||||
int j_cl = 0;
|
||||
for (int idx = 0; idx < qam->M; idx++) {
|
||||
double d = cabs(r - qam->constellation[idx]);
|
||||
if (d < min_d) {
|
||||
min_d = d;
|
||||
i_cl = idx / qam->sm;
|
||||
j_cl = idx % qam->sm;
|
||||
}
|
||||
}
|
||||
|
||||
// Gray mapping
|
||||
if (qam->k % 2 != 0) {
|
||||
printf("demodulate : k pair (k = %d)\n", qam->k);
|
||||
exit(1);
|
||||
}
|
||||
int bits_per_axis = qam->k / 2;
|
||||
|
||||
int i_bin = gray_to_bin(i_cl);
|
||||
int j_bin = gray_to_bin(j_cl);
|
||||
|
||||
for (int b = 0; b < bits_per_axis; b++) {
|
||||
bits_hat[k * qam->k + b] = (i_bin >> (bits_per_axis - 1 - b)) & 1;
|
||||
bits_hat[k * qam->k + bits_per_axis + b] = (j_bin >> (bits_per_axis - 1 - b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calcul du bruit gaussien pour un sigma donné
|
||||
// Formule de Box-Muller
|
||||
double gaussian_noise (double sigma) {
|
||||
double u1 = (rand() + 1) / ((double)RAND_MAX + 2);
|
||||
double u2 = (rand() + 1) / ((double)RAND_MAX + 2);
|
||||
return sigma * sqrt(-2 * log(u1)) * cos(2 * M_PI * u2);
|
||||
}
|
||||
|
||||
// Ajout du bruit
|
||||
void add_noise (double complex* s, int len, double sigma) {
|
||||
//double signal_power = (2.0/3.0)*(qam.M-1);
|
||||
//double snr_dB = 5; // SNR en dB
|
||||
//double snr_lin = pow(10.0, snr_dB / 10.0);
|
||||
//double sigma = sqrt(signal_power / snr_lin);
|
||||
for (int i = 0; i < len; i++) {
|
||||
double nr = gaussian_noise(sigma);
|
||||
double ni = gaussian_noise(sigma);
|
||||
s[i] += nr + I * ni;
|
||||
}
|
||||
}
|
||||
|
||||
// Changer le tableau de bits en boolen ou alors la represenation binaire et shifter pour extraire les bits (pas bien si M plus grand)
|
||||
void bits_to_symbols (qam_system* qam, uint8_t* bits, int nb_bits, double complex* symbols) {
|
||||
int nb_symbols = nb_bits / qam->k;
|
||||
|
||||
// k pair
|
||||
if (qam->k % 2 != 0) {
|
||||
printf("bits_to_symbols : k doit être pair (k = %d) \n", qam->k);
|
||||
exit(1);
|
||||
}
|
||||
int bits_per_axis = qam->k / 2;
|
||||
|
||||
for (int sym = 0; sym < nb_symbols; sym++) {
|
||||
// Construire les indices binaires i_bin (MSB...) et j_bin (LSB...)
|
||||
int i_bin = 0;
|
||||
int j_bin = 0;
|
||||
for (int b = 0; b < bits_per_axis; b++) {
|
||||
i_bin = (i_bin << 1) | bits[sym * qam->k + b];
|
||||
j_bin = (j_bin << 1) | bits[sym * qam->k + bits_per_axis + b];
|
||||
}
|
||||
|
||||
int i_gray = bin_to_gray(i_bin);
|
||||
int j_gray = bin_to_gray(j_bin);
|
||||
|
||||
if (i_gray < 0 || i_gray >= qam->sm || j_gray < 0 || j_gray >= qam->sm) {
|
||||
printf("bits_to_symbols : IOOR i_gray = %d j_gray = %d sm = %d \n", i_gray, j_gray, qam->sm);
|
||||
exit(1);
|
||||
}
|
||||
symbols[sym] = qam->constellation[i_gray * qam->sm + j_gray];
|
||||
}
|
||||
}
|
||||
|
||||
double compare_bits(uint8_t* bits1, uint8_t* bits2, int nb_bits) {
|
||||
int errors = 0;
|
||||
for (int i = 0; i < nb_bits; i++) {
|
||||
if (bits1[i] != bits2[i]) errors++;
|
||||
}
|
||||
return (double)errors / nb_bits;
|
||||
}
|
||||
|
||||
void add_dephasage(double complex* s, double phi_offset, int total_samples) {
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
s[i] *= cexp(I * phi_offset);
|
||||
}
|
||||
}
|
||||
|
||||
void add_freq(qam_system* qam, double complex* s, double freq_offset, int total_samples) {
|
||||
for (int i = 0; i < total_samples; i++) {
|
||||
double t = (double)i / qam->Fs;
|
||||
s[i] *= cexp(I * 2 * M_PI * freq_offset * t);
|
||||
}
|
||||
}
|
||||
|
||||
void fill_constellation_data(qam_system* qam, FILE *fp_ref) {
|
||||
for (int i = 0; i < qam->sm; i++) {
|
||||
for (int j = 0; j < qam->sm; j++) {
|
||||
int idx = i * qam->sm + j;
|
||||
fprintf(fp_ref, "% .8f % .8f\n", creal(qam->constellation[idx]), cimag(qam->constellation[idx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reconstruction_text(int nb_chars, uint8_t* output_bits, char* texte_recup) {
|
||||
for(int i = 0; i < nb_chars; i++){
|
||||
char c = 0;
|
||||
for(int b = 0; b < 8; b++){
|
||||
c |= output_bits[i*8 + b] << (7-b);
|
||||
}
|
||||
texte_recup[i] = c;
|
||||
}
|
||||
texte_recup[nb_chars] = '\0';
|
||||
}
|
||||
|
||||
void text_to_bits(int nb_chars, int nb_bits, char* texte, uint8_t* input_bits) {
|
||||
for(int i = 0; i < nb_chars; i++){
|
||||
for(int b = 0; b < 8; b++){
|
||||
input_bits[i*8 + b] = (texte[i] >> (7-b)) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Libération de la mémoire
|
||||
void free_constellation(qam_system* qam) {
|
||||
free(qam->constellation);
|
||||
}
|
||||
|
||||
int main () {
|
||||
// Initialisation du system qam
|
||||
qam_system qam;
|
||||
qam.M = 16;
|
||||
qam.k = (int)log2((double)(qam.M));
|
||||
qam.sm = (int)sqrt(qam.M);
|
||||
qam.Fs = 44100;
|
||||
qam.Ts = 0.01;
|
||||
qam.N = (int)(qam.Fs * qam.Ts);
|
||||
qam.Fc = 2000;
|
||||
init_constellation(&qam);
|
||||
|
||||
// Conversion du texte en bits
|
||||
char* texte = "Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux, Vif juge, trempez ce blond whisky aqueux";
|
||||
int nb_chars = strlen(texte);
|
||||
int nb_bits = nb_chars * 8;
|
||||
int nb_symbols = (nb_bits + qam.k - 1) / qam.k;
|
||||
uint8_t* input_bits = malloc(nb_bits * sizeof(uint8_t));
|
||||
text_to_bits(nb_chars, nb_bits, texte, input_bits);
|
||||
|
||||
// Conversion en symboles
|
||||
double complex* symbols = malloc(sizeof(double complex) * nb_symbols);
|
||||
bits_to_symbols(&qam, input_bits, nb_bits, symbols);
|
||||
|
||||
// Modulation
|
||||
int total_samples = qam.N * nb_symbols;
|
||||
double complex* s = malloc(sizeof(double complex) * total_samples);
|
||||
modulate(&qam, symbols, nb_symbols, s);
|
||||
|
||||
// Ajout du bruit
|
||||
add_noise(s, total_samples, 0);
|
||||
|
||||
FILE *fp_ref = fopen("constellation_ref.dat", "w");
|
||||
fill_constellation_data(&qam, fp_ref);
|
||||
fclose(fp_ref);
|
||||
|
||||
// Ajout de dephasage
|
||||
//add_dephasage(s, M_PI / 6.0, total_samples);
|
||||
|
||||
// AJout de decalage de fréquence
|
||||
//add_freq(&qam, s, 1, total_samples);
|
||||
|
||||
// Démodulation
|
||||
FILE *fp_constel = fopen("constellation.dat", "w");
|
||||
uint8_t* output_bits = (uint8_t*)malloc(nb_bits * sizeof(uint8_t));
|
||||
demodulate(&qam, s, nb_symbols, output_bits, fp_constel);
|
||||
fclose(fp_constel);
|
||||
|
||||
// Reconstruction du texte
|
||||
char* texte_recup = malloc(nb_chars + 1);
|
||||
reconstruction_text(nb_chars, output_bits, texte_recup);
|
||||
|
||||
printf("Texte original : %s\n\n", texte);
|
||||
printf("Texte demodulé : %s\n", texte_recup);
|
||||
|
||||
// Calcul du BER
|
||||
double ber = compare_bits(input_bits, output_bits, nb_bits);
|
||||
printf("Taux d'erreur blind QAM: %.4f\n", ber * 100);
|
||||
|
||||
// Libération mémoire
|
||||
free(input_bits);
|
||||
free(output_bits);
|
||||
free(symbols);
|
||||
free(s);
|
||||
free_constellation(&qam);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user