Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 55 additions & 59 deletions src/math/freq_shift.rs
Original file line number Diff line number Diff line change
@@ -1,87 +1,80 @@
use futuresdr::blocks::signal_source::NCO;
use futuresdr::macros::Block;
use futuresdr::num_complex::Complex32;
use futuresdr::runtime::Block;
use futuresdr::runtime::BlockMeta;
use futuresdr::runtime::BlockMetaBuilder;
use futuresdr::runtime::Kernel;
use futuresdr::runtime::MessageIo;
use futuresdr::runtime::MessageIoBuilder;
use futuresdr::runtime::Result;
use futuresdr::runtime::StreamIo;
use futuresdr::runtime::StreamIoBuilder;
use futuresdr::runtime::WorkIo;
use futuresdr::prelude::{
BlockMeta, CpuBufferReader, CpuBufferWriter, DefaultCpuReader, DefaultCpuWriter, Kernel,
MessageOutputs, WorkIo, Result,
};

/// This blocks shift the signal in the frequency domain based on the [`NCO`] implementation.
/// This block shifts the signal in the frequency domain based on the [`NCO`] implementation.
/// Currently implemented only for float and [`Complex32`]
///
/// # Usage
///
/// ```
/// # use futuresdr::num_complex::Complex32;
/// # use fsdr_blocks::math::FrequencyShifter;
/// # let freq = 2_000;
/// # let sample_rate = 48_000;
/// use futuresdr::num_complex::Complex32;
/// use fsdr_blocks::math::FrequencyShifter;
/// let freq = 2_000;
/// let sample_rate = 48_000;
/// let blk = FrequencyShifter::<Complex32>::new(freq as f32, sample_rate as f32);
/// ```
pub struct FrequencyShifter<A>
#[derive(Block)]
pub struct FrequencyShifter<T, I = DefaultCpuReader<T>, O = DefaultCpuWriter<T>>
where
A: Send + 'static + Copy,
T: Copy + Send + 'static,
I: CpuBufferReader<Item = T>,
O: CpuBufferWriter<Item = T>,
{
_p1: std::marker::PhantomData<A>,
#[input]
input: I,
#[output]
output: O,
nco: NCO,
}

impl<A> FrequencyShifter<A>
impl<T, I, O> FrequencyShifter<T, I, O>
where
A: Send + 'static + Copy,
FrequencyShifter<A>: futuresdr::runtime::Kernel,
T: Copy + Send + 'static,
I: CpuBufferReader<Item = T>,
O: CpuBufferWriter<Item = T>,
{
#[allow(clippy::new_ret_no_self)]
pub fn new(frequency: f32, sample_rate: f32) -> Block {
let nco = NCO::new(
0.0f32,
2.0 * core::f32::consts::PI * frequency / sample_rate,
);
Block::new(
BlockMetaBuilder::new("FrequencyShift").build(),
StreamIoBuilder::new()
.add_input::<A>("in")
.add_output::<A>("out")
.build(),
MessageIoBuilder::<Self>::new().build(),
FrequencyShifter {
_p1: std::marker::PhantomData,
nco,
},
)
pub fn new(frequency: f32, sample_rate: f32) -> Self {
Self {
input: I::default(),
output: O::default(),
nco: NCO::new(0.0f32, core::f32::consts::TAU * frequency / sample_rate),
}
}
}

#[doc(hidden)]
#[async_trait]
impl Kernel for FrequencyShifter<f32> {
impl<I, O> Kernel for FrequencyShifter<f32, I, O>
where
I: CpuBufferReader<Item = f32>,
O: CpuBufferWriter<Item = f32>,
{
async fn work(
&mut self,
io: &mut WorkIo,
sio: &mut StreamIo,
_mio: &mut MessageIo<Self>,
_mio: &mut MessageOutputs,
_meta: &mut BlockMeta,
) -> Result<()> {
let i = sio.input(0).slice::<f32>();
let o = sio.output(0).slice::<f32>();
let i = self.input.slice();
let o = self.output.slice();
let i_len = i.len();

let m = std::cmp::min(i.len(), o.len());
let m = std::cmp::min(i_len, o.len());
if m > 0 {
for (v, r) in i.iter().zip(o.iter_mut()) {
*r = (*v) * self.nco.phase.cos();
self.nco.step();
}

sio.input(0).consume(m);
sio.output(0).produce(m);
self.input.consume(m);
self.output.produce(m);
}

if sio.input(0).finished() && m == i.len() {
if self.input.finished() && m == i_len {
io.finished = true;
}

Expand All @@ -90,30 +83,33 @@ impl Kernel for FrequencyShifter<f32> {
}

#[doc(hidden)]
#[async_trait]
impl Kernel for FrequencyShifter<Complex32> {
impl<I, O> Kernel for FrequencyShifter<Complex32, I, O>
where
I: CpuBufferReader<Item = Complex32>,
O: CpuBufferWriter<Item = Complex32>,
{
async fn work(
&mut self,
io: &mut WorkIo,
sio: &mut StreamIo,
_mio: &mut MessageIo<Self>,
_mio: &mut MessageOutputs,
_meta: &mut BlockMeta,
) -> Result<()> {
let i = sio.input(0).slice::<Complex32>();
let o = sio.output(0).slice::<Complex32>();
let i = self.input.slice();
let o = self.output.slice();
let i_len = i.len();

let m = std::cmp::min(i.len(), o.len());
let m = std::cmp::min(i_len, o.len());
if m > 0 {
for (v, r) in i.iter().zip(o.iter_mut()) {
*r = (*v) * Complex32::new(self.nco.phase.cos(), self.nco.phase.sin());
self.nco.step();
}

sio.input(0).consume(m);
sio.output(0).produce(m);
self.input.consume(m);
self.output.produce(m);
}

if sio.input(0).finished() && m == i.len() {
if self.input.finished() && m == i_len {
io.finished = true;
}

Expand Down
Loading