From 369a83bcfd8c244699afc2a4afbcc99ea8230bb7 Mon Sep 17 00:00:00 2001 From: zeefaad Date: Fri, 13 Feb 2026 15:30:36 +0100 Subject: [PATCH] analyse complete --- Code/ldpc/src/analysis.rs | 208 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/Code/ldpc/src/analysis.rs b/Code/ldpc/src/analysis.rs index e69de29..f30329f 100644 --- a/Code/ldpc/src/analysis.rs +++ b/Code/ldpc/src/analysis.rs @@ -0,0 +1,208 @@ +use crate::channel::Channel; +use crate::code::LdpcCode; +use crate::construction::random::generate_random_h_for_k; +use crate::decoder::bit_flip::BitFlipDecoder; +use crate::encoder::dense::DenseEncoder; +use rand::{Rng, RngExt}; +use rayon::prelude::*; +use std::fs::File; +use std::io::Write; + +#[derive(Debug, Clone, Copy)] +pub enum DecoderAlgorithm { + BitFlipping, +} + +#[derive(Clone)] +pub struct AnalysisConfig { + pub k_values: Vec, + pub wc_values: Vec, + pub wr_values: Vec, + pub min_error_prob: f64, + pub max_error_prob: f64, + pub steps: usize, + pub frames_per_step: usize, + pub max_iter: usize, + pub algorithm: DecoderAlgorithm, +} + +#[derive(Debug, Clone)] +pub struct SimulationPoint { + pub k_config: usize, + pub n_real: usize, + pub wc: usize, + pub wr: usize, + pub rate: f64, + pub error_rate: f64, + pub ber: f64, + pub fer: f64, + pub avg_iter: f64, +} + +pub struct Analyzer; + +impl Analyzer { + pub fn run_batch(config: AnalysisConfig) -> Vec { + let mut tasks = Vec::new(); + + for &k in &config.k_values { + for &wc in &config.wc_values { + for &wr in &config.wr_values { + if wr <= wc { + continue; + } + if (k * wr) % (wr - wc) != 0 { + continue; + } + tasks.push((k, wc, wr)); + } + } + } + + println!("Configurations valides : {}", tasks.len()); + println!("Execution sur {} coeurs...", rayon::current_num_threads()); + + let results: Vec = tasks + .par_iter() + .flat_map(|&(k_target, wc, wr)| { + let h_matrix = generate_random_h_for_k(k_target, wc, wr); + let ldpc = LdpcCode::new(h_matrix); + let encoder = DenseEncoder::new(&ldpc); + + let k_real = encoder.k; + let n_real = encoder.n; + let rate_theoretical = k_real as f64 / n_real as f64; + + let step_size = if config.steps > 1 { + (config.max_error_prob - config.min_error_prob) / (config.steps as f64 - 1.0) + } else { + 0.0 + }; + + (0..config.steps) + .into_par_iter() + .map(|i| { + let p = config.min_error_prob + (i as f64 * step_size); + + let point = Self::simulate_point( + &encoder, + &ldpc, + p, + &config, + k_real, + k_target, + n_real, + wc, + wr, + rate_theoretical, + ); + + println!( + "Termine : k={} wc={} wr={} p={:.3} -> BER={:.5}", + point.k_config, point.wc, point.wr, point.error_rate, point.ber + ); + + point + }) + .collect::>() + }) + .collect(); + + println!("Simulation terminee. {} points generes.", results.len()); + results + } + + fn simulate_point( + encoder: &DenseEncoder, + ldpc: &LdpcCode, + p: f64, + config: &AnalysisConfig, + k_real: usize, + k_orig: usize, + n: usize, + wc: usize, + wr: usize, + rate: f64, + ) -> SimulationPoint { + let channel = Channel::new(p); + let mut rng = rand::rng(); + + let mut total_bit_errors = 0; + let mut total_frame_errors = 0; + let mut total_iterations = 0; + let mut converged_count = 0; + + for _ in 0..config.frames_per_step { + let message: Vec = (0..k_real).map(|_| rng.random_range(0..2)).collect(); + let codeword = encoder.encode(&message); + let received = channel.add_noise(&codeword); + + let (decoded, iters) = match config.algorithm { + DecoderAlgorithm::BitFlipping => { + let decoder = BitFlipDecoder::new(ldpc); + let res = decoder.decode(&received, config.max_iter); + (res, 0) + } + }; + + match decoded { + Some(res_code) => { + if res_code != codeword { + total_frame_errors += 1; + total_bit_errors += Channel::count_errors(&codeword, &res_code); + } else { + converged_count += 1; + total_iterations += iters; + } + } + None => { + total_frame_errors += 1; + total_bit_errors += Channel::count_errors(&codeword, &received); + } + } + } + + let total_bits = (config.frames_per_step * n) as f64; + let avg_iter = if converged_count > 0 { + total_iterations as f64 / converged_count as f64 + } else { + config.max_iter as f64 + }; + + SimulationPoint { + k_config: k_orig, + n_real: n, + wc, + wr, + rate, + error_rate: p, + ber: total_bit_errors as f64 / total_bits, + fer: total_frame_errors as f64 / config.frames_per_step as f64, + avg_iter, + } + } + + pub fn save_csv(results: &[SimulationPoint], filename: &str) { + let mut sorted_results = results.to_vec(); + sorted_results.sort_by(|a, b| { + a.k_config + .cmp(&b.k_config) + .then(a.wc.cmp(&b.wc)) + .then(a.wr.cmp(&b.wr)) + .then(a.error_rate.partial_cmp(&b.error_rate).unwrap()) + }); + + let mut file = File::create(filename).expect("Erreur fichier"); + writeln!(file, "k,n,wc,wr,rate,p,ber,fer,avg_iter").unwrap(); + + for r in sorted_results { + writeln!( + file, + "{},{},{},{},{:.4},{:.6},{:.8},{:.8},{:.2}", + r.k_config, r.n_real, r.wc, r.wr, r.rate, r.error_rate, r.ber, r.fer, r.avg_iter + ) + .unwrap(); + } + println!("Resultats sauvegardes dans '{}'", filename); + } +}