pub struct Otfs {
pub n_fft: usize,
pub n_symbols: usize,
pub n_cp: usize,
pub sample_rate: Hertz,
}Expand description
An OTFS modem: n_fft delay bins $M$ (the subcarriers), n_symbols Doppler bins $N$
(the symbols of a frame) and one prefix of n_cp samples per frame (see the module).
Fields§
§n_fft: usizeDelay bins $M$, the subcarriers of the Heisenberg transform.
n_symbols: usizeDoppler bins $N$, the symbols of a frame.
n_cp: usizeThe cyclic prefix of a frame, in samples (OTFS has no oversampling: one sample per delay bin).
sample_rate: HertzThe rate of the samples, $M \Delta f$: the rate of the Signal of Modulate
and the rate Demodulate expects; 1 Hz by default (time in samples).
Implementations§
Source§impl Otfs
impl Otfs
Sourcepub fn new(n_fft: usize, n_symbols: usize) -> Result<Otfs>
pub fn new(n_fft: usize, n_symbols: usize) -> Result<Otfs>
$M$ delay bins and $N$ Doppler bins, no prefix, at the sample rate 1 Hz.
§Errors
Error::Config for an empty grid.
Sourcepub fn check(&self) -> Result<()>
pub fn check(&self) -> Result<()>
Validate the configuration.
§Errors
Error::Config for an empty grid, a prefix longer than the frame or a sample
rate that is not positive and finite.
Sourcepub fn modulate(&self, x: &[C64]) -> Result<Vec<C64>>
pub fn modulate(&self, x: &[C64]) -> Result<Vec<C64>>
Modulate the frames of x, each $MN$ symbols $x[nM + m] = X[m, n]$ (the
columns of $X$ one after the other), with the prefix.
§Errors
Error::Config for an invalid configuration, Error::Shape unless x holds
whole frames.
Sourcepub fn demodulate(&self, r: &[C64]) -> Result<Vec<C64>>
pub fn demodulate(&self, r: &[C64]) -> Result<Vec<C64>>
Demodulate whole frames: drop the prefix, DFT along the Doppler axis.
§Errors
Error::Config for an invalid configuration, Error::Shape unless r holds
whole frames.
Sourcepub fn effective_channel(&self, paths: &[Path]) -> Result<EffectiveChannel>
pub fn effective_channel(&self, paths: &[Path]) -> Result<EffectiveChannel>
The effective delay–Doppler channel of paths at Otfs::sample_rate: the
$MN \times MN$ matrix of Theorem 1 of Raviteja et al. (2019), eq. (12), with
$z = e^{j 2\pi/(MN)}$ and the Doppler shifts in bins $k_{i} = \nu_{i} MN / f_{s}$
(of either sign),
$$ T^{(i)}(p, q) = \begin{cases} e^{-j 2\pi n/N} z^{k_{i}([m - l_{i}]{M})} & m < l{i}, \\ z^{k_{i}([m - l_{i}]{M})} & m \ge l{i}, \end{cases} \qquad q = [m - l_{i}]{M} + M[n - k{i}]_{N}, $$
$p = nM + m$, zero elsewhere, summed with the gains: one entry per path in every
row (EffectiveChannel). The time of a path counts from the first sample of the
frame, its prefix included, as in comnum_channel::multipath::DelayDoppler: the gain
of eq. (6), whose time starts after the prefix, is
$h_{i} e^{j 2\pi k_{i} N_{\mathrm{cp}}/(MN)}$. The model assumes a prefix at least
as long as the largest delay.
§Errors
Error::Config for an invalid configuration, a delay of $M$ samples or more, or
a Doppler shift that is not a whole number of bins (Otfs::transform_channel
takes any channel).
§Examples
use comnum_waveform::otfs::Otfs;
use comnum_core::channel::Path;
use comnum_core::units::Hertz;
use comnum_math::C64;
// M N = 32 samples at 32 kHz: one Doppler bin is 1 kHz
let o = Otfs { sample_rate: Hertz(32e3), ..Otfs::new(8, 4)? };
let h = o.effective_channel(&[Path { gain: C64::new(1.0, 0.0), delay: 1, doppler_hz: 1e3 }])?;
assert_eq!((h.size(), h.n_paths()), (32, 1));
let x: Vec<C64> = (0..32).map(|i| C64::new(i as f64, 0.0)).collect();
let y = h.apply(&x)?;
let dense = h.to_dense();
assert!((0..32).all(|p| ((0..32).map(|q| dense[[p, q]] * x[q]).sum::<C64>() - y[p]).norm() < 1e-12));Sourcepub fn transform_channel(&self, h: &CMat) -> Result<CMat>
pub fn transform_channel(&self, h: &CMat) -> Result<CMat>
The effective channel $(F_{N} \otimes I_{M}) H (F_{N}^{H} \otimes I_{M})$ of a
time-domain channel matrix h ($MN \times MN$, acting on the frame without its
prefix), for any delays and Doppler shifts (eq. (13)).
$F_{N}^{H} \otimes I_{M}$ is symmetric, so the right product transforms every row of $H$ and the left one every column of the result, each by $M$ FFTs of $N$ points: $O((MN)^{2} \log N)$ operations.
§Errors
Error::Shape unless h is $MN \times MN$.
Trait Implementations§
impl Copy for Otfs
Source§impl Demodulate for Otfs
OTFS as a Demodulate block: one stream of samples at Otfs::sample_rate.
impl Demodulate for Otfs
OTFS as a Demodulate block: one stream of samples at Otfs::sample_rate.
Source§fn demodulate_into(&mut self, y: &Signal, out: &mut Symbols) -> Result<()>
fn demodulate_into(&mut self, y: &Signal, out: &mut Symbols) -> Result<()>
§Errors
Error::Config for several streams or a signal at another sample rate, and the
errors of Otfs::demodulate.
Source§impl Modulate for Otfs
OTFS as a Modulate block: one stream of delay–Doppler symbols into one stream of
samples at Otfs::sample_rate.
impl Modulate for Otfs
OTFS as a Modulate block: one stream of delay–Doppler symbols into one stream of
samples at Otfs::sample_rate.