#[inline]
pub fn db2lin(x_db: f64) -> f64 {
10f64.powf(x_db / 10.0)
}
#[inline]
pub fn lin2db(x: f64) -> f64 {
10.0 * x.log10()
}
#[inline]
pub fn db2amp(x_db: f64) -> f64 {
10f64.powf(x_db / 20.0)
}
#[inline]
pub fn amp2db(x: f64) -> f64 {
20.0 * x.log10()
}
#[inline]
pub fn db2np(x_db: f64) -> f64 {
x_db / (10.0 * std::f64::consts::LOG10_E)
}
#[inline]
pub fn np2db(x_np: f64) -> f64 {
10.0 * std::f64::consts::LOG10_E * x_np
}
#[inline]
pub fn dbm2w(p_dbm: f64) -> f64 {
1e-3 * db2lin(p_dbm)
}
#[inline]
pub fn w2dbm(p_w: f64) -> f64 {
lin2db(p_w / 1e-3)
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
pub struct Db(pub f64);
impl Db {
pub fn to_linear(self) -> f64 {
db2lin(self.0)
}
pub fn from_linear(x: f64) -> Db {
Db(lin2db(x))
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
pub struct EbN0(pub Db);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
pub struct EsN0(pub Db);
impl EbN0 {
pub fn to_es_n0(self, bits_per_symbol: f64, rate: f64) -> EsN0 {
EsN0(Db(self.0.0 + lin2db(bits_per_symbol * rate)))
}
}
impl EsN0 {
pub fn to_eb_n0(self, bits_per_symbol: f64, rate: f64) -> EbN0 {
EbN0(Db(self.0.0 - lin2db(bits_per_symbol * rate)))
}
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
pub struct Hertz(pub f64);
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Default)]
pub struct Seconds(pub f64);
impl Hertz {
pub fn period(self) -> Seconds {
Seconds(1.0 / self.0)
}
}
impl Seconds {
pub fn frequency(self) -> Hertz {
Hertz(1.0 / self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn conversions_round_trip() {
let eb = EbN0(Db(6.0));
let back = eb.to_es_n0(4.0, 0.75).to_eb_n0(4.0, 0.75);
assert!((back.0.0 - 6.0).abs() < 1e-12);
assert!((Hertz(32e9).period().frequency().0 - 32e9).abs() < 1e-3);
assert!((Db::from_linear(Db(-7.5).to_linear()).0 + 7.5).abs() < 1e-12);
}
}