Muller & Muller (RRC needed to be implemented...)
This commit is contained in:
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);
|
||||
|
||||
Reference in New Issue
Block a user