This commit is contained in:
2026-06-01 09:12:47 +02:00
parent 9c3fb79c00
commit a7ff55e942
9 changed files with 1 additions and 1857 deletions

View File

@ -1,192 +0,0 @@
use crate::{Gf2, LdpcError, Llr, Result};
// Trait Channel
pub trait Channel: Send + Sync {
fn transmit(&self, codeword: &[Gf2], rng: &mut impl rand::Rng) -> Vec<Llr>;
fn capacity(&self) -> f64;
}
// Canal AWGN
// Modulation BPSK : 0 -> +1.0, 1 -> -1.0
// Signal reçu : y = x + n, n eq N(0, sig²)
// LLR optimal : L(y) = 2y/sig²
// sig² = N_0/2 = 1/(2 R SNR_lin)
#[derive(Debug, Clone)]
pub struct AwgnChannel {
pub snr_db: f64,
sigma: f64,
}
impl AwgnChannel {
pub fn new(snr_db: f64, code_rate: f64) -> Result<Self> {
if !(0.0..1.0).contains(&code_rate) {
return Err(LdpcError::OutOfRange("code_rate ∈ ]0, 1[".into()));
}
let snr_lin = 10.0_f64.powf(snr_db / 10.0);
let sigma = (1.0 / (2.0 * code_rate * snr_lin)).sqrt();
Ok(Self { snr_db, sigma })
}
pub fn sigma(&self) -> f64 {
self.sigma
}
pub fn snr_linear(&self) -> f64 {
10.0_f64.powf(self.snr_db / 10.0)
}
#[inline]
pub fn llr_from_received(y: f64, sigma: f64) -> Llr {
2.0 * y / (sigma * sigma)
}
}
impl Channel for AwgnChannel {
fn transmit(&self, codeword: &[Gf2], rng: &mut impl rand::Rng) -> Vec<Llr> {
use rand_distr::{Distribution, Normal};
let normal = Normal::new(0.0, self.sigma).unwrap();
codeword
.iter()
.map(|&b| {
let x = if b == 0 { 1.0_f64 } else { -1.0_f64 };
let y = x + normal.sample(rng);
Self::llr_from_received(y, self.sigma)
})
.collect()
}
fn capacity(&self) -> f64 {
// Capacité BPSK-AWGN par Monte-Carlo
use rand_distr::{Distribution, Normal};
let mut rng = rand::thread_rng();
let normal = Normal::new(0.0, self.sigma).unwrap();
let n_samples = 10_000usize;
let mut sum = 0.0f64;
for _ in 0..n_samples {
let n: f64 = normal.sample(&mut rng);
let y = 1.0 + n; // bit 0 transmis (x=+1)
let llr = Self::llr_from_received(y, self.sigma);
// I = 1 - E[log2(1 + exp(-2y/sig²))]
sum += (1.0 + (-llr).exp()).log2();
}
1.0 - sum / n_samples as f64
}
}
// Canal BSC
// Chaque bit inversé avec probabilité p
// LLR : +-log((1-p)/p) selon le bit reçu
#[derive(Debug, Clone)]
pub struct BscChannel {
pub crossover_prob: f64,
llr_magnitude: Llr,
}
impl BscChannel {
pub fn new(crossover_prob: f64) -> Result<Self> {
if crossover_prob <= 0.0 || crossover_prob >= 0.5 {
return Err(LdpcError::OutOfRange("p ∈ ]0, 0.5[".into()));
}
let llr_magnitude = ((1.0 - crossover_prob) / crossover_prob).ln();
Ok(Self {
crossover_prob,
llr_magnitude,
})
}
}
impl Channel for BscChannel {
fn transmit(&self, codeword: &[Gf2], rng: &mut impl rand::Rng) -> Vec<Llr> {
codeword
.iter()
.map(|&b| {
let rcv = if rng.gen::<f64>() < self.crossover_prob {
b ^ 1
} else {
b
};
if rcv == 0 {
self.llr_magnitude
} else {
-self.llr_magnitude
}
})
.collect()
}
// C_BSC(p) = 1 - Hb(p) avec Hb = entropie binaire
fn capacity(&self) -> f64 {
let p = self.crossover_prob;
let hb = -p * p.log2() - (1.0 - p) * (1.0 - p).log2();
1.0 - hb
}
}
// Canal BEC
// Bit effacé avec probabilité ε -> LLR = 0 (incertitude totale)
// Bit reçu correctement → LLR = +-CERTAIN_LLR (grand mais fini)
#[derive(Debug, Clone)]
pub struct BecChannel {
pub erasure_prob: f64,
}
impl BecChannel {
pub fn new(erasure_prob: f64) -> Result<Self> {
if erasure_prob <= 0.0 || erasure_prob >= 1.0 {
return Err(LdpcError::OutOfRange("ε ∈ ]0, 1[".into()));
}
Ok(Self { erasure_prob })
}
// Grand mais fini pour stabilité numérique
const CERTAIN_LLR: Llr = 100.0;
}
impl Channel for BecChannel {
fn transmit(&self, codeword: &[Gf2], rng: &mut impl rand::Rng) -> Vec<Llr> {
codeword
.iter()
.map(|&b| {
if rng.gen::<f64>() < self.erasure_prob {
0.0 // Effacement
} else if b == 0 {
Self::CERTAIN_LLR
} else {
-Self::CERTAIN_LLR
}
})
.collect()
}
/// C_BEC(ε) = 1 - ε
fn capacity(&self) -> f64 {
1.0 - self.erasure_prob
}
}
// #[cfg(test)]
// mod tests {
// use super::*;
//
// #[test]
// fn test_awgn_llr_formula() {
// assert!((AwgnChannel::llr_from_received(1.0, 1.0) - 2.0).abs() < 1e-12);
// assert!((AwgnChannel::llr_from_received(-1.0, 1.0) + 2.0).abs() < 1e-12);
// }
//
// #[test]
// fn test_bec_capacity() {
// let bec = BecChannel::new(0.3).unwrap();
// assert!((bec.capacity() - 0.7).abs() < 1e-12);
// }
//
// #[test]
// fn test_bsc_capacity_bounds() {
// let bsc = BscChannel::new(0.1).unwrap();
// let cap = bsc.capacity();
// assert!(cap > 0.0 && cap < 1.0);
// }
// }