Muller & Muller (RRC needed to be implemented...)

This commit is contained in:
2025-10-24 12:28:31 +02:00
parent 43238e304e
commit 880d6cdfac
15 changed files with 185450 additions and 4197 deletions

116
QAM/qam.c
View File

@ -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);