190 lines
6.0 KiB
C
190 lines
6.0 KiB
C
#include <math.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <complex.h>
|
|
#include "../WAV/wav.h"
|
|
#include "../files/files.h"
|
|
#include <string.h>
|
|
|
|
#define A 10000
|
|
|
|
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] = A * (ip + I * qp) / norm_factor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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];
|
|
}
|
|
}
|
|
|
|
// 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++) {
|
|
s[k * qam->N + n] = iq * cexp(2 * I * M_PI * qam->Fc * ((double)n / qam->Fs));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Demodulation qam
|
|
void demodulate(qam_system* qam, double complex* s, int nb_symbols, uint8_t* bits_hat, double sigma) {
|
|
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;
|
|
|
|
// Distance euclidien de Ir et Qr pour avoir le point le plus proche de la constellation
|
|
|
|
int sm = (int)sqrt(qam->M);
|
|
/* TEMPS INFINI
|
|
double min_d = INFINITY;
|
|
int i_cl, 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;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
double norm_factor = sqrt((double)(qam->M - 1) / 3.0);
|
|
double Ir = creal(r) * norm_factor / A;
|
|
double Qr = cimag(r) * norm_factor / A;
|
|
|
|
int i = (int)round((Ir + (sm - 1)) / 2.0);
|
|
int j = (int)round((Qr + (sm - 1)) / 2.0);
|
|
|
|
i = (i < 0) ? 0 : ((i >= sm) ? sm - 1 : i);
|
|
j = (j < 0) ? 0 : ((j >= sm) ? sm - 1 : j);
|
|
|
|
int id = i * sm + j;
|
|
|
|
//int id = i_cl * sm + j_cl;
|
|
for (int b = 0; b < qam->k; b++) {
|
|
bits_hat[k * qam->k + (qam->k - 1 - b)] = (id >> 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 (int argc, char *argv[]) {
|
|
if (argc < 2) {
|
|
fprintf(stderr, "Utilisation: %s <fichier_entree>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
qam_system qam;
|
|
qam.M = 256;
|
|
qam.k = (int)log2((double)(qam.M));
|
|
qam.Fs = 44100;
|
|
qam.Ts = 0.00003;
|
|
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");
|
|
// 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");
|
|
// 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");
|
|
// 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);
|
|
|
|
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);
|
|
|
|
printf("Ecriture...\n");
|
|
// Ecriture du fichier de Demodulation
|
|
char *output_filename = make_output_filename(input_filename);
|
|
bits_to_file(output_filename, &output_bits);
|
|
|
|
|
|
// Affichage du signal dans un .wav
|
|
double* si = (double*)malloc(sizeof(double) * total_samples);
|
|
for (int i = 0; i < total_samples; i++) {
|
|
si[i] = cimag(s[i]);
|
|
}
|
|
write_wav("s.wav", si, total_samples);
|
|
|
|
// Libération mémoire
|
|
free_bit_array(&input_bits);
|
|
free_bit_array(&output_bits);
|
|
free(symbols);
|
|
free(s);
|
|
free_constellation(&qam);
|
|
free(output_filename);
|
|
|
|
return 0;
|
|
}
|