Skip to main content

Cpm

Struct Cpm 

Source
pub struct Cpm { /* private fields */ }
Expand description

A CPM modulator and its detectors (see the module documentation).

Implementations§

Source§

impl Cpm

Source

pub const MAX_DIFFERENCE_SEQUENCES: usize

The largest number of difference sequences Cpm::min_distance2 visits.

Source

pub fn ml_detect(&self, r: &[C64]) -> Result<Vec<usize>>

The coherent maximum-likelihood sequence detector (Viterbi algorithm over the phase trellis): the symbol indices of the most likely sequence, starting from the initial state of the modulator and ending in any state.

§Errors

comnum_core::Error::Shape unless r holds a positive whole number of symbols.

§Examples
use comnum_waveform::cpm::{CpmConfig, FrequencyPulse};
let cpm = CpmConfig { order: 4, h_num: 1, h_den: 4, pulse: FrequencyPulse::RaisedCosine, length: 2, sps: 4 }.build()?;
let a = vec![0, 3, 1, 2, 2, 0, 1, 3, 3, 0];
assert_eq!(cpm.ml_detect(&cpm.modulate(&a)?)?, a);
Source

pub fn ml_detect_path(&self, r: &[C64]) -> Result<MlPath>

The maximum-likelihood sequence with its terminal phase states (see MlPath).

§Errors

As Cpm::ml_detect.

Source

pub fn msk_detect(&self, r: &[C64]) -> Result<Vec<u8>>

The quadrature detector of MSK: the boundary bits $d_{n}$, $n = 1 \dots N$ ($d_{n} = +1$ is the bit 1), decided from $\operatorname{Re}\left[(-j)^{n} \int_{(n-1)T}^{(n+1)T} r(t) \cos \frac{\pi (t - nT)}{2T} \, dt\right]$ (the last window is truncated to the signal). Over AWGN, each decision has the error probability $Q(\sqrt{2 E_{b}/N_{0}})$ of antipodal signalling.

§Errors

comnum_core::Error::Config unless the signal is MSK, comnum_core::Error::Shape unless it holds a whole number of symbols.

Source

pub fn differential_detect( &self, r: &[C64], rx_bt: Option<f64>, ) -> Result<Vec<usize>>

The one-symbol differential phase detector of binary CPM: after an optional low-pass predetection filter of normalised 3 dB bandwidth rx_bt (None for no filter; the band-pass bandwidth $B_{i}$ of Simon & Wang, 1984, is twice this value, and about $0.5/T$ is the best choice for MSK), the signal is sampled every symbol at $t_{n} = (n + (L + 1)/2) T$, where the phase increment $\varphi(t_{n}) - \varphi(t_{n-1})$ depends most on $a_{n}$ (for an even $L$ and an odd sps the instant is rounded down to a sample), and $\hat{a}{n} = \operatorname{sign} \operatorname{Im} (r{n} r_{n-1}^{\ast})$. A symbol whose instant falls after the end of the signal uses its last sample.

For MSK without filter the increment is exactly $\pi a_{n}/2$; the partial response of GMSK closes the eye, so the detector degrades with $BT$.

§Errors

comnum_core::Error::Config unless the signal is binary or if rx_bt is not positive, comnum_core::Error::Shape unless it holds a whole number of symbols.

Source

pub fn min_distance2(&self, max_len: usize) -> Result<f64>

The normalised minimum squared Euclidean distance over the pairs of sequences that diverge at $t = 0$ and merge again within max_len symbols (the upper bound $d_{B}^{2}$ of Anderson, Aulin & Sundberg, ch. 3, which is the true $d_{\min}^{2}$ when the shortest merge is the closest one, as for MSK):

$$ d^{2} = \frac{\log_{2} M}{T} \int_{0}^{(N + L - 1) T} \left[1 - \cos \Delta \varphi(t)\right] dt, \qquad \Delta \varphi(t) = 2 \pi h \sum_{k=0}^{N-1} \gamma_{k} \, q(t - kT), $$

over the difference sequences $\gamma_{k} = a_{k} - a_{k}^{\prime} \in \{0, \pm 2, \dots, \pm 2(M-1)\}$ with $\gamma_{0} \ne 0$ and $\pi h \sum_{k} \gamma_{k} \equiv 0 \pmod{2 \pi}$ (the merge). The integral is evaluated by Simpson’s rule with 256 intervals per symbol (within $10^{-9}$ of the closed form $2(1 - \operatorname{sinc} 2h)$ of binary CPFSK); it is infinite if no sequence merges within max_len symbols. With this normalisation antipodal signalling has $d^{2} = 2$. The search visits $(2M - 1)^{N}$ difference sequences for max_len $= N$, at most Cpm::MAX_DIFFERENCE_SEQUENCES; with max_len $= 0$ it visits none and returns infinity.

§Errors

Error::Config if $(2M - 1)^{N}$ exceeds Cpm::MAX_DIFFERENCE_SEQUENCES (at max_len = 20, binary CPM would visit $3.5 \cdot 10^{9}$ sequences).

§Examples
use comnum_waveform::cpm::CpmConfig;
let msk = CpmConfig::msk(4).build()?;
assert!((msk.min_distance2(3)? - 2.0).abs() < 1e-3);
assert!(msk.min_distance2(20).is_err());
Source§

impl Cpm

Source

pub fn config(&self) -> &CpmConfig

The validated parameters (the modulation index in lowest terms).

Source

pub fn with_sample_rate(self, sample_rate: Hertz) -> Result<Cpm>

The same modulator at the sample rate sample_rate (sps samples per symbol) of the verb traits.

§Errors

comnum_core::Error::Config for a sample rate that is not positive and finite.

§Examples
use comnum_core::prelude::*;
use comnum_waveform::cpm::CpmConfig;
let mut msk = CpmConfig::msk(8).build()?.with_sample_rate(Hertz(8e3))?;
let a = Labels::from_stream(vec![1, 0, 0, 1, 1])?;
let s = Modulate::modulate(&msk, &a)?;
assert_eq!((s.len(), s.sample_rate()), (40, Hertz(8e3)));
assert_eq!(Demodulate::<Labels>::demodulate(&mut msk, &s)?, a);
Source

pub fn sample_rate(&self) -> Hertz

The sample rate of the signal of the verb traits (1 Hz unless set by Cpm::with_sample_rate).

Source

pub fn h(&self) -> f64

The modulation index $h = p/q$.

Source

pub fn n_phase_states(&self) -> usize

The number of terminal phases, $2q$ (the trellis visits $q$ of them when $p$ is even).

Source

pub fn n_states(&self) -> usize

The number of trellis states, $2q M^{L-1}$.

Source

pub fn symbol_value(&self, index: usize) -> f64

The symbol value $a = 2i - (M - 1)$ of the index i.

Source

pub fn phase_response(&self) -> &[f64]

The tabulated phase response, $q(k T / \mathrm{sps})$ for $k < L \cdot \mathrm{sps}$.

Source

pub fn phase(&self, symbols: &[usize]) -> Result<Vec<f64>>

The phase of the signal at every sample, with the terminal phase reduced modulo $2 \pi$ (the phase is continuous across the intervals up to these $2 \pi$ jumps).

§Errors

comnum_core::Error::Config if a symbol index is not below $M$.

Source

pub fn modulate(&self, symbols: &[usize]) -> Result<Vec<C64>>

The complex baseband signal $e^{j \varphi(t)}$ at sps samples per symbol.

§Errors

comnum_core::Error::Config if a symbol index is not below $M$.

Trait Implementations§

Source§

impl Clone for Cpm

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Cpm

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Demodulate<Labels> for Cpm

CPM as a Demodulate block: the coherent maximum-likelihood sequence detector Cpm::ml_detect on one stream of samples at Cpm::sample_rate.

Source§

fn demodulate_into(&mut self, y: &Signal, out: &mut Labels) -> Result<()>

§Errors

comnum_core::Error::Config for several streams or a signal at another sample rate, and the errors of Cpm::ml_detect.

Source§

fn demodulate(&mut self, y: &Signal) -> Result<Out, Error>
where Out: Default,

Demodulate y (allocates, calls Demodulate::demodulate_into). Read more
Source§

impl Modulate<Labels> for Cpm

CPM as a Modulate block: one stream of symbol indices into one stream of samples at Cpm::sample_rate, by Cpm::modulate.

Source§

fn modulate_into(&self, x: &Labels, out: &mut Signal) -> Result<()>

§Errors

comnum_core::Error::Config for several streams, and the errors of Cpm::modulate.

Source§

fn modulate(&self, x: &In) -> Result<Signal, Error>

Modulate x (allocates, calls Modulate::modulate_into). Read more
Source§

impl PartialEq for Cpm

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Cpm

Auto Trait Implementations§

§

impl Forget for Cpm

§

impl Freeze for Cpm

§

impl RefUnwindSafe for Cpm

§

impl Send for Cpm

§

impl Sync for Cpm

§

impl Unpin for Cpm

§

impl UnsafeUnpin for Cpm

§

impl UnwindSafe for Cpm

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.