QAM add constellation plot
This commit is contained in:
58
QAM/qam.c
58
QAM/qam.c
@ -3,9 +3,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
#include "../WAV/wav.h"
|
#include "../wav/wav.h"
|
||||||
#include "../files/files.h"
|
#include "../files/files.h"
|
||||||
|
#include "../plot/plot_constellation.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#define A 10000
|
#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) {
|
void modulate (qam_system* qam, double complex* symbols, int nb_symbols, double complex* s) {
|
||||||
for (int k = 0; k < nb_symbols; k++) {
|
for (int k = 0; k < nb_symbols; k++) {
|
||||||
double complex iq = 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
|
// Demodulation QAM
|
||||||
void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat, double sigma) {
|
void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat) {
|
||||||
for (int k = 0; k < nb_symbols; k++) {
|
for (int k = 0; k < nb_symbols; k++) {
|
||||||
double complex r = 0;
|
double complex r = 0;
|
||||||
for (int n = 0; n < qam->N; n++) {
|
for (int n = 0; n < qam->N; n++) {
|
||||||
@ -128,6 +130,19 @@ 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
|
// Libération de la mémoire
|
||||||
void free_constellation(qam_system* qam) {
|
void free_constellation(qam_system* qam) {
|
||||||
int sm = (int)sqrt(qam->M);
|
int sm = (int)sqrt(qam->M);
|
||||||
@ -143,50 +158,46 @@ int main (int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qam_system qam;
|
qam_system qam;
|
||||||
qam.M = 256;
|
qam.M = 64;
|
||||||
qam.k = (int)log2((double)(qam.M));
|
qam.k = (int)log2((double)(qam.M));
|
||||||
qam.Fs = 44100;
|
qam.Fs = 44100;
|
||||||
qam.Ts = 0.003;
|
qam.Ts = 0.0003;
|
||||||
qam.N = (int)qam.Fs * qam.Ts;
|
qam.N = (int)qam.Fs * qam.Ts;
|
||||||
qam.Fc = 2000;
|
qam.Fc = 2000;
|
||||||
init_constellation(&qam);
|
init_constellation(&qam);
|
||||||
|
|
||||||
// Nombre de bit multiple de k sinon remplir de zero jusqu'a ce que ce le soit
|
printf("Lecture du fichier...\n");
|
||||||
//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");
|
|
||||||
// Lecture du fichier et conversion en bits
|
// Lecture du fichier et conversion en bits
|
||||||
const char *input_filename = argv[1];
|
const char *input_filename = argv[1];
|
||||||
bit_array input_bits = file_to_bits(input_filename);
|
bit_array input_bits = file_to_bits(input_filename);
|
||||||
size_t nb_symbols = input_bits.nb_bits / qam.k;
|
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
|
// Mise en forme des symboles
|
||||||
double complex *symbols = malloc(sizeof(double complex) * nb_symbols);
|
double complex *symbols = malloc(sizeof(double complex) * nb_symbols);
|
||||||
bits_to_symbols(&qam, input_bits.bits, input_bits.nb_bits, symbols);
|
bits_to_symbols(&qam, input_bits.bits, input_bits.nb_bits, symbols);
|
||||||
|
|
||||||
printf("Modulation\n");
|
printf("Modulation...\n");
|
||||||
// Modulation QAM
|
// Modulation QAM
|
||||||
int total_samples = qam.N * nb_symbols;
|
int total_samples = qam.N * nb_symbols;
|
||||||
double complex* s = (double complex*)malloc(sizeof(double complex) * total_samples);
|
double complex* s = (double complex*)malloc(sizeof(double complex) * total_samples);
|
||||||
modulate(&qam, symbols, nb_symbols, s);
|
modulate(&qam, symbols, nb_symbols, s);
|
||||||
|
|
||||||
// Ajout du bruit
|
// Ajout du bruit
|
||||||
double signal_power = (2.0/3.0)*(qam.M-1); // puissance moyenne avant échelle
|
double signal_power = (2.0/3.0)*(qam.M-1); // puissance moyenne avant échelle
|
||||||
double snr_dB = -27; // Signal to noise ratio
|
double snr_dB = -27; // Signal to noise ratio
|
||||||
double snr_lin = pow(10.0, snr_dB / 10.0);
|
double snr_lin = pow(10.0, snr_dB / 10.0);
|
||||||
double sigma = sqrt(signal_power / snr_lin);
|
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);
|
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);
|
add_noise(s, total_samples, 1875);
|
||||||
|
|
||||||
printf("Demodulation\n");
|
printf("Demodulation...\n");
|
||||||
|
|
||||||
// Demodulation QAM
|
// Demodulation QAM
|
||||||
bit_array output_bits;
|
bit_array output_bits;
|
||||||
output_bits.nb_bits = input_bits.nb_bits;
|
output_bits.nb_bits = input_bits.nb_bits;
|
||||||
output_bits.bits = (uint8_t*)malloc(output_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");
|
printf("Ecriture...\n");
|
||||||
// Ecriture du fichier de Demodulation
|
// Ecriture du fichier de Demodulation
|
||||||
@ -199,9 +210,18 @@ int main (int argc, char *argv[]) {
|
|||||||
for (int i = 0; i < total_samples; i++) {
|
for (int i = 0; i < total_samples; i++) {
|
||||||
si[i] = cimag(s[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
|
// Libération mémoire
|
||||||
|
plot_close(&plot);
|
||||||
free_bit_array(&input_bits);
|
free_bit_array(&input_bits);
|
||||||
free_bit_array(&output_bits);
|
free_bit_array(&output_bits);
|
||||||
free(symbols);
|
free(symbols);
|
||||||
|
|||||||
113
plot/plot_constellation.c
Normal file
113
plot/plot_constellation.c
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#include "plot_constellation.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
|
||||||
35
plot/plot_constellation.h
Normal file
35
plot/plot_constellation.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef PLOT_CONSTELLATION_H
|
||||||
|
#define PLOT_CONSTELLATION_H
|
||||||
|
|
||||||
|
#include <complex.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
Reference in New Issue
Block a user