diff --git a/QAM/qam b/QAM/qam index 95b9039..8f1a68b 100755 Binary files a/QAM/qam and b/QAM/qam differ diff --git a/QAM/qam.c b/QAM/qam.c index 624629e..d770894 100644 --- a/QAM/qam.c +++ b/QAM/qam.c @@ -3,9 +3,11 @@ #include #include #include -#include "../WAV/wav.h" +#include "../wav/wav.h" #include "../files/files.h" +#include "../plot/plot_constellation.h" #include +#include #define A 10000 @@ -73,7 +75,7 @@ void bits_to_symbols (qam_system* qam, uint8_t* bits, int nb_bits, double comple } } -// Modulation qam +// 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]; @@ -83,8 +85,8 @@ void modulate (qam_system* qam, double complex* symbols, int nb_symbols, double } } -// Demodulation qam -void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat, double sigma) { +// Demodulation QAM +void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat) { for (int k = 0; k < nb_symbols; k++) { double complex r = 0; for (int n = 0; n < qam->N; n++) { @@ -128,8 +130,21 @@ void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bit } } +double complex* demodulate_points(qam_system* qam, double complex* s, int nb_symbols) { + double complex* points = malloc(sizeof(double complex) * nb_symbols); + 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)n / qam->Fs)); + } + r /= qam->N; + points[k] = r; + } + return points; +} + // Libération de la mémoire -void free_constellation(qam_system *qam) { +void free_constellation(qam_system* qam) { int sm = (int)sqrt(qam->M); for (int i = 0; i < sm; i++) free(qam->constellation[i]); @@ -143,50 +158,46 @@ int main (int argc, char *argv[]) { } qam_system qam; - qam.M = 256; + qam.M = 64; qam.k = (int)log2((double)(qam.M)); qam.Fs = 44100; - qam.Ts = 0.003; + qam.Ts = 0.0003; qam.N = (int)qam.Fs * qam.Ts; qam.Fc = 2000; init_constellation(&qam); - // Nombre de bit multiple de k sinon remplir de zero jusqu'a ce que ce le soit - //int bits[16] = {1,0,1,1, 0,1,1,0, 1,1,0,0, 0,0,0,1}; - //int nb_bits = 16; - //int nb_symbols = 16 / qam.k; - - printf("Lecture du fichier\n"); + printf("Lecture du fichier...\n"); // Lecture du fichier et conversion en bits const char *input_filename = argv[1]; bit_array input_bits = file_to_bits(input_filename); size_t nb_symbols = input_bits.nb_bits / qam.k; - printf("Mise en forme des symboles\n"); + printf("Mise en forme des symboles...\n"); // Mise en forme des symboles double complex *symbols = malloc(sizeof(double complex) * nb_symbols); bits_to_symbols(&qam, input_bits.bits, input_bits.nb_bits, symbols); - printf("Modulation\n"); + printf("Modulation...\n"); // Modulation QAM int total_samples = qam.N * nb_symbols; double complex* s = (double complex*)malloc(sizeof(double complex) * total_samples); modulate(&qam, symbols, nb_symbols, s); + // Ajout du bruit double signal_power = (2.0/3.0)*(qam.M-1); // puissance moyenne avant échelle double snr_dB = -27; // Signal to noise ratio double snr_lin = pow(10.0, snr_dB / 10.0); double sigma = sqrt(signal_power / snr_lin); - printf("Ajout du bruit \n puissance du signal : %f\n SNR db : %f\n sigma : %f\n", signal_power, snr_dB, sigma); - add_noise(s, total_samples, sigma); + printf("Ajout du bruit... \n puissance du signal : %f\n SNR db : %f\n sigma : %f\n", signal_power, snr_dB, sigma); + add_noise(s, total_samples, 1875); - printf("Demodulation\n"); + printf("Demodulation...\n"); // Demodulation QAM bit_array output_bits; output_bits.nb_bits = input_bits.nb_bits; output_bits.bits = (uint8_t*)malloc(output_bits.nb_bits); - demodulate(&qam, s, nb_symbols, output_bits.bits, 0.0); + demodulate(&qam, s, nb_symbols, output_bits.bits); printf("Ecriture...\n"); // Ecriture du fichier de Demodulation @@ -199,9 +210,18 @@ int main (int argc, char *argv[]) { for (int i = 0; i < total_samples; i++) { si[i] = cimag(s[i]); } - write_wav("s.wav", si, total_samples); + write_wav("output.wav", si, total_samples); + + // Plot + printf("Ploting..."); + plot_t plot; + plot_init(&plot, 1400, 1400, 0.04); + plot_draw_constellation(&plot, qam.constellation, qam.M); + SDL_Color red = {255, 0, 0, 255}; + plot_draw_points_animated(&plot, demodulate_points(&qam, s, nb_symbols), nb_symbols, red, 5); // Libération mémoire + plot_close(&plot); free_bit_array(&input_bits); free_bit_array(&output_bits); free(symbols); diff --git a/plot/plot_constellation.c b/plot/plot_constellation.c new file mode 100644 index 0000000..3b10cfd --- /dev/null +++ b/plot/plot_constellation.c @@ -0,0 +1,113 @@ +#include "plot_constellation.h" +#include +#include +#include + +// Fonction utilitaire pour dessiner un cercle plein +static void draw_filled_circle(SDL_Renderer* renderer, int cx, int cy, int radius) { + for (int w = -radius; w <= radius; w++) { + for (int h = -radius; h <= radius; h++) { + if (w*w + h*h <= radius*radius) { + SDL_RenderDrawPoint(renderer, cx + w, cy + h); + } + } + } +} + +// Initialisation SDL +void plot_init(plot_t *plot, int width, int height, double scale) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + fprintf(stderr, "Erreur SDL_Init: %s\n", SDL_GetError()); + exit(1); + } + + plot->width = width; + plot->height = height; + plot->scale = scale; + plot->offset_x = width / 2.0; + plot->offset_y = height / 2.0; + + plot->window = SDL_CreateWindow("Constellation QAM", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + width, height, SDL_WINDOW_SHOWN); + if (!plot->window) { fprintf(stderr, "Erreur SDL_CreateWindow: %s\n", SDL_GetError()); exit(1); } + + plot->renderer = SDL_CreateRenderer(plot->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!plot->renderer) { fprintf(stderr, "Erreur SDL_CreateRenderer: %s\n", SDL_GetError()); exit(1); } + + SDL_SetRenderDrawColor(plot->renderer, 0, 0, 0, 255); // fond noir + SDL_RenderClear(plot->renderer); + SDL_RenderPresent(plot->renderer); +} + +// Dessiner la constellation (grille verte) +void plot_draw_constellation(plot_t *plot, double complex **constellation, int M) { + int sm = (int)sqrt(M); + SDL_SetRenderDrawColor(plot->renderer, 0, 255, 0, 255); // vert + + int radius = 8; // gros cercle pour la grille + for (int i = 0; i < sm; i++) { + for (int j = 0; j < sm; j++) { + int x = (int)(creal(constellation[i][j]) * plot->scale + plot->offset_x); + int y = (int)(cimag(constellation[i][j]) * plot->scale + plot->offset_y); + draw_filled_circle(plot->renderer, x, y, radius); + } + } + SDL_RenderPresent(plot->renderer); +} + +// Dessiner un tableau de points complexes (rouges) +void plot_draw_points(plot_t *plot, double complex *points, int nb_points, SDL_Color color) { + int radius = 4; // plus petit que la grille verte + SDL_SetRenderDrawColor(plot->renderer, color.r, color.g, color.b, color.a); + + for (int k = 0; k < nb_points; k++) { + int x = (int)(creal(points[k]) * plot->scale + plot->offset_x); + int y = (int)(cimag(points[k]) * plot->scale + plot->offset_y); + draw_filled_circle(plot->renderer, x, y, radius); + } + SDL_RenderPresent(plot->renderer); +} + +// Dessiner les points progressivement avec animation +void plot_draw_points_animated(plot_t *plot, double complex *points, int nb_points, SDL_Color color, int delay_ms) { + int radius = 4; + int k; + + for (k = 0; k < nb_points; k++) { + SDL_SetRenderDrawColor(plot->renderer, color.r, color.g, color.b, color.a); + int x = (int)(creal(points[k]) * plot->scale + plot->offset_x); + int y = (int)(cimag(points[k]) * plot->scale + plot->offset_y); + draw_filled_circle(plot->renderer, x, y, radius); + SDL_RenderPresent(plot->renderer); + + // Gestion événements pour stopper animation + SDL_Event event; + int stop = 0; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) return; + if (event.type == SDL_KEYDOWN) { stop = 1; break; } + } + if (stop) break; + + SDL_Delay(delay_ms); + } + + // Après animation ou keypress, attendre fermeture ou keypress + int running = 1; + SDL_Event event; + while (running) { + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) running = 0; + if (event.type == SDL_KEYDOWN) running = 0; + } + SDL_Delay(10); + } +} + +// Fermer SDL +void plot_close(plot_t *plot) { + SDL_DestroyRenderer(plot->renderer); + SDL_DestroyWindow(plot->window); + SDL_Quit(); +} + diff --git a/plot/plot_constellation.h b/plot/plot_constellation.h new file mode 100644 index 0000000..a6aeaf1 --- /dev/null +++ b/plot/plot_constellation.h @@ -0,0 +1,35 @@ +#ifndef PLOT_CONSTELLATION_H +#define PLOT_CONSTELLATION_H + +#include +#include + +typedef struct { + SDL_Window *window; + SDL_Renderer *renderer; + int width; + int height; + double scale; + double offset_x; + double offset_y; +} plot_t; + +// Initialiser SDL et la fenêtre +void plot_init(plot_t *plot, int width, int height, double scale); + +// Dessiner la constellation (grille de départ) +void plot_draw_constellation(plot_t *plot, double complex **constellation, int M); + +// Dessiner un tableau de points complexes +void plot_draw_points(plot_t *plot, double complex *points, int nb_points, SDL_Color color); + +// Dessiner les points progressivement avec animation +// delay_ms = délai entre chaque point en millisecondes +// Keypress pendant animation coupe l’animation +void plot_draw_points_animated(plot_t *plot, double complex *points, int nb_points, SDL_Color color, int delay_ms); + +// Fermer SDL proprement +void plot_close(plot_t *plot); + +#endif + diff --git a/WAV/wav.c b/wav/wav.c similarity index 100% rename from WAV/wav.c rename to wav/wav.c diff --git a/WAV/wav.h b/wav/wav.h similarity index 100% rename from WAV/wav.h rename to wav/wav.h