A few DSP blocks
This commit is contained in:
89
Cargo.lock
generated
89
Cargo.lock
generated
@ -2,6 +2,12 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
@ -55,11 +61,21 @@ dependencies = [
|
||||
name = "ntw"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ntw_dsp",
|
||||
"ntw_flowgraph",
|
||||
"ntw_flowgraph_macros",
|
||||
"ringbuf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntw_dsp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ntw_flowgraph",
|
||||
"ntw_flowgraph_macros",
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntw_flowgraph"
|
||||
version = "0.1.0"
|
||||
@ -78,6 +94,79 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.3"
|
||||
|
||||
@ -6,4 +6,5 @@ edition = "2024"
|
||||
[dependencies]
|
||||
ntw_flowgraph = {path = "ntw_flowgraph"}
|
||||
ntw_flowgraph_macros = {path = "ntw_flowgraph_macros"}
|
||||
ntw_dsp = {path = "ntw_dsp"}
|
||||
ringbuf = "0.4.8"
|
||||
|
||||
1
ntw_dsp/.gitignore
vendored
Normal file
1
ntw_dsp/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
260
ntw_dsp/Cargo.lock
generated
Normal file
260
ntw_dsp/Cargo.lock
generated
Normal file
@ -0,0 +1,260 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntw_dsp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ntw_flowgraph",
|
||||
"ntw_flowgraph_macros",
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntw_flowgraph"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ntw_flowgraph_macros",
|
||||
"petgraph",
|
||||
"ringbuf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntw_flowgraph_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"hashbrown 0.15.5",
|
||||
"indexmap",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ringbuf"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe47b720588c8702e34b5979cb3271a8b1842c7cb6f57408efa70c779363488c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
9
ntw_dsp/Cargo.toml
Normal file
9
ntw_dsp/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "ntw_dsp"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
ntw_flowgraph = {path = "../ntw_flowgraph/"}
|
||||
ntw_flowgraph_macros = {path = "../ntw_flowgraph_macros/"}
|
||||
num = "0.4.3"
|
||||
5
ntw_dsp/src/blocks.rs
Normal file
5
ntw_dsp/src/blocks.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub mod complex;
|
||||
pub mod iter;
|
||||
pub mod map;
|
||||
pub mod nco;
|
||||
pub mod tee;
|
||||
24
ntw_dsp/src/blocks/complex.rs
Normal file
24
ntw_dsp/src/blocks/complex.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use ntw_flowgraph::Block;
|
||||
use ntw_flowgraph::inout::{In, Out};
|
||||
use ntw_flowgraph_macros::Block;
|
||||
use num::Complex;
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct Im<T>
|
||||
{
|
||||
#[input]
|
||||
input: In<Complex<T>>,
|
||||
|
||||
#[output]
|
||||
output: Out<T>,
|
||||
}
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct Re<T>
|
||||
{
|
||||
#[input]
|
||||
input: In<Complex<T>>,
|
||||
|
||||
#[output]
|
||||
output: Out<T>,
|
||||
}
|
||||
50
ntw_dsp/src/blocks/iter.rs
Normal file
50
ntw_dsp/src/blocks/iter.rs
Normal file
@ -0,0 +1,50 @@
|
||||
use std::iter::Peekable;
|
||||
|
||||
use ntw_flowgraph::{
|
||||
BlockWork,
|
||||
inout::{In, Out, Stream},
|
||||
};
|
||||
use ntw_flowgraph_macros::Block;
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct IterSource<T, I>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
iter: Peekable<I>,
|
||||
|
||||
#[output]
|
||||
output: Out<T>,
|
||||
}
|
||||
|
||||
impl<T, I> IterSource<T, I>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
pub fn new(iter: I) -> (Self, In<T>)
|
||||
{
|
||||
let (output, input) = Stream::make(1024);
|
||||
(
|
||||
Self {
|
||||
iter: iter.peekable(),
|
||||
output,
|
||||
},
|
||||
input,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I> BlockWork for IterSource<T, I>
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
fn work(&mut self)
|
||||
{
|
||||
self.output.push_iter(&mut self.iter);
|
||||
}
|
||||
|
||||
fn ready(&mut self) -> bool
|
||||
{
|
||||
self.iter.peek().is_some() && self.output.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
45
ntw_dsp/src/blocks/map.rs
Normal file
45
ntw_dsp/src/blocks/map.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use ntw_flowgraph::{
|
||||
Block, BlockWork,
|
||||
inout::{In, Out, Stream},
|
||||
};
|
||||
use ntw_flowgraph_macros::Block;
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct Map<I, O, F>
|
||||
where
|
||||
F: Fn(I) -> O,
|
||||
{
|
||||
#[input]
|
||||
input: In<I>,
|
||||
|
||||
#[output]
|
||||
output: Out<O>,
|
||||
|
||||
map: F,
|
||||
}
|
||||
|
||||
impl<I, O, F> Map<I, O, F>
|
||||
where
|
||||
F: Fn(I) -> O,
|
||||
{
|
||||
pub fn new(input: In<I>, map: F) -> (Self, In<O>)
|
||||
{
|
||||
let (output, b) = Stream::make(1024);
|
||||
(Self { input, output, map }, b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, O, F> BlockWork for Map<I, O, F>
|
||||
where
|
||||
F: Fn(I) -> O,
|
||||
{
|
||||
fn work(&mut self)
|
||||
{
|
||||
self.output.push_iter(self.input.pop_iter().map(&self.map));
|
||||
}
|
||||
|
||||
fn ready(&self) -> bool
|
||||
{
|
||||
self.input.available_len() > 0 && self.output.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
52
ntw_dsp/src/blocks/nco.rs
Normal file
52
ntw_dsp/src/blocks/nco.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use ntw_flowgraph::Block;
|
||||
use ntw_flowgraph::inout::{In, Stream};
|
||||
use ntw_flowgraph::{BlockWork, inout::Out};
|
||||
use ntw_flowgraph_macros::Block;
|
||||
use num::Complex;
|
||||
|
||||
use crate::Frequency;
|
||||
use crate::generation::Nco;
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct ComplexNco<T>
|
||||
{
|
||||
inner: crate::generation::Nco<T>,
|
||||
|
||||
#[output]
|
||||
out: Out<Complex<T>>,
|
||||
}
|
||||
|
||||
impl BlockWork for ComplexNco<f32>
|
||||
{
|
||||
fn work(&mut self)
|
||||
{
|
||||
self.out.push_iter(&mut self.inner);
|
||||
}
|
||||
|
||||
fn ready(&self) -> bool
|
||||
{
|
||||
self.out.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockWork for ComplexNco<f64>
|
||||
{
|
||||
fn work(&mut self)
|
||||
{
|
||||
self.out.push_iter(&mut self.inner);
|
||||
}
|
||||
|
||||
fn ready(&self) -> bool
|
||||
{
|
||||
self.out.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ComplexNco<T>
|
||||
{
|
||||
pub fn new(nco: Nco<T>) -> (Self, In<Complex<T>>)
|
||||
{
|
||||
let (a, b) = Stream::make(1024);
|
||||
(Self { inner: nco, out: a }, b)
|
||||
}
|
||||
}
|
||||
57
ntw_dsp/src/blocks/tee.rs
Normal file
57
ntw_dsp/src/blocks/tee.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use ntw_flowgraph_macros::Block;
|
||||
use ntw_flowgraph::{Block, BlockWork, inout::{In, Out, Stream}};
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct Tee<T>
|
||||
{
|
||||
#[input]
|
||||
input: In<T>
|
||||
|
||||
#[output]
|
||||
output_1: Out<T>
|
||||
|
||||
#[output]
|
||||
output_2: Out<T>
|
||||
}
|
||||
|
||||
impl<T> Tee<T>
|
||||
{
|
||||
pub fn new(input: In<T>) -> (Tee<T>, In<T>, In<T>)
|
||||
{
|
||||
let (output_1, in_1) = Stream::make(1024);
|
||||
let (output_2, in_2) = Stream::make(1024);
|
||||
(
|
||||
Tee
|
||||
{
|
||||
input,
|
||||
output_1,
|
||||
output_2,
|
||||
},
|
||||
in_1,
|
||||
in_2
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> BlockWork for Tee<T>
|
||||
{
|
||||
fn work(&mut self)
|
||||
{
|
||||
let len = self.output_1.vacant_len().min(self.output_2.vacant_len())
|
||||
.min(self.input.available_len());
|
||||
|
||||
for _ in 0..len
|
||||
{
|
||||
let elem = self.input.try_pop().unwrap(); // Should be available because of len check
|
||||
|
||||
self.output_1.try_push(elem.clone());
|
||||
self.output_2.try_push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
fn ready(&self) -> bool {
|
||||
self.input.available_len() > 0 &&
|
||||
self.output_1.vacant_len() > 0 &&
|
||||
self.output_2.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
111
ntw_dsp/src/generation.rs
Normal file
111
ntw_dsp/src/generation.rs
Normal file
@ -0,0 +1,111 @@
|
||||
use std::{f64::consts::PI, marker::PhantomData};
|
||||
|
||||
use num::Complex;
|
||||
|
||||
use crate::Frequency;
|
||||
|
||||
pub struct Nco<T>
|
||||
{
|
||||
// Phase offset : 0 = 0, usize::MAX = 2*pi
|
||||
phase: usize,
|
||||
|
||||
// Frequency : d(erivative) of phase
|
||||
// Radians per sample
|
||||
d_phase: Frequency,
|
||||
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Nco<T>
|
||||
{
|
||||
pub fn new(frequency: Frequency) -> Self
|
||||
{
|
||||
Nco::<T> {
|
||||
phase: 0,
|
||||
d_phase: frequency,
|
||||
_phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_frequency(&mut self, frequency: Frequency)
|
||||
{
|
||||
self.d_phase = frequency;
|
||||
}
|
||||
|
||||
pub fn set_phase(&mut self, phase: f64)
|
||||
{
|
||||
self.phase = ((phase / (2. * PI)) * usize::MAX as f64).floor() as usize;
|
||||
}
|
||||
|
||||
pub fn step(&mut self)
|
||||
{
|
||||
let (new, _) = self.phase.overflowing_add(self.d_phase.0);
|
||||
self.phase = new;
|
||||
}
|
||||
}
|
||||
|
||||
impl Nco<f32>
|
||||
{
|
||||
pub fn sample_sin(&self) -> f32
|
||||
{
|
||||
let t = (self.phase as f32 / usize::MAX as f32) * 2. * std::f32::consts::PI;
|
||||
t.sin()
|
||||
}
|
||||
|
||||
pub fn sample_cos(&self) -> f32
|
||||
{
|
||||
let t = (self.phase as f32 / usize::MAX as f32) * 2. * std::f32::consts::PI;
|
||||
t.cos()
|
||||
}
|
||||
|
||||
pub fn sample(&self) -> Complex<f32>
|
||||
{
|
||||
let t = (self.phase as f32 / usize::MAX as f32) * 2. * std::f32::consts::PI;
|
||||
Complex::new(t.cos(), t.sin())
|
||||
}
|
||||
}
|
||||
|
||||
impl Nco<f64>
|
||||
{
|
||||
pub fn sample_sin(&self) -> f64
|
||||
{
|
||||
let t = (self.phase as f64 / usize::MAX as f64) * 2. * std::f64::consts::PI;
|
||||
t.sin()
|
||||
}
|
||||
|
||||
pub fn sample_cos(&self) -> f64
|
||||
{
|
||||
let t = (self.phase as f64 / usize::MAX as f64) * 2. * std::f64::consts::PI;
|
||||
t.cos()
|
||||
}
|
||||
|
||||
pub fn sample(&self) -> Complex<f64>
|
||||
{
|
||||
let t = (self.phase as f64 / usize::MAX as f64) * 2. * std::f64::consts::PI;
|
||||
Complex::new(t.cos(), t.sin())
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Nco<f32>
|
||||
{
|
||||
type Item = Complex<f32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
let v = self.sample();
|
||||
self.step();
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Nco<f64>
|
||||
{
|
||||
type Item = Complex<f64>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item>
|
||||
{
|
||||
let v = self.sample();
|
||||
self.step();
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
37
ntw_dsp/src/lib.rs
Normal file
37
ntw_dsp/src/lib.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use std::f64::consts::PI;
|
||||
|
||||
pub mod blocks;
|
||||
pub mod generation;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct Frequency(pub usize);
|
||||
|
||||
impl Frequency
|
||||
{
|
||||
pub fn from_rad(radians_per_sample: f64) -> Frequency
|
||||
{
|
||||
let f = euclid_mod(radians_per_sample, 2. * PI);
|
||||
Frequency(((f / (2. * PI)) * (usize::MAX as f64)).floor() as usize)
|
||||
}
|
||||
|
||||
pub fn as_rad(&self) -> f64
|
||||
{
|
||||
((self.0 as f64) / (usize::MAX as f64)) * 2. * PI
|
||||
}
|
||||
|
||||
pub fn from_frequency(frequency: f64, sample_rate: f64) -> Frequency
|
||||
{
|
||||
Self::from_rad((frequency / sample_rate) * 2. * PI)
|
||||
}
|
||||
|
||||
pub fn as_frequency(&self, sample_rate: f64) -> f64
|
||||
{
|
||||
(self.as_rad() / (2. * PI)) * sample_rate
|
||||
}
|
||||
}
|
||||
|
||||
fn euclid_mod(a: f64, m: f64) -> f64
|
||||
{
|
||||
let r = a % m;
|
||||
if r < 0.0 { r + m } else { r }
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
use crate::Block;
|
||||
use crate::{Block, BlockWork, RunnableBlock};
|
||||
use petgraph::graph::DiGraph;
|
||||
|
||||
pub struct Graph
|
||||
{
|
||||
blocks: Vec<Box<dyn Block>>,
|
||||
blocks: Vec<Box<dyn RunnableBlock>>,
|
||||
}
|
||||
|
||||
impl Graph
|
||||
@ -13,7 +13,7 @@ impl Graph
|
||||
Graph { blocks: vec![] }
|
||||
}
|
||||
|
||||
pub fn add_block(&mut self, block: impl Block + 'static)
|
||||
pub fn add_block(&mut self, block: impl Block + BlockWork + 'static)
|
||||
{
|
||||
block.set_block_index(self.blocks.len());
|
||||
self.blocks.push(Box::new(block));
|
||||
@ -23,14 +23,16 @@ impl Graph
|
||||
{
|
||||
// Compute the topo_order
|
||||
let mut digraph = DiGraph::<(), (), usize>::with_capacity(self.blocks.len(), 1);
|
||||
let len = self.blocks.len();
|
||||
(0..len).for_each(|_| {
|
||||
digraph.add_node(());
|
||||
});
|
||||
|
||||
for block in self.blocks.iter()
|
||||
for (i, block) in self.blocks.iter().enumerate()
|
||||
{
|
||||
let node = digraph.add_node(());
|
||||
|
||||
for next in block.get_successors()
|
||||
{
|
||||
digraph.add_edge(node, next.into(), ());
|
||||
digraph.add_edge(i.into(), next.into(), ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ use ringbuf::SharedRb;
|
||||
use ringbuf::consumer::PopIter;
|
||||
use ringbuf::storage::Heap;
|
||||
use ringbuf::traits::Consumer;
|
||||
use ringbuf::traits::Observer;
|
||||
use ringbuf::traits::Producer;
|
||||
use ringbuf::traits::Split;
|
||||
use ringbuf::wrap::caching::Caching;
|
||||
@ -61,6 +62,11 @@ impl<T> In<T>
|
||||
{
|
||||
self.rb.pop_iter()
|
||||
}
|
||||
|
||||
pub fn available_len(&self) -> usize
|
||||
{
|
||||
self.rb.occupied_len()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Out<T>
|
||||
@ -81,4 +87,9 @@ impl<T> Out<T>
|
||||
{
|
||||
self.rb.push_iter(iter)
|
||||
}
|
||||
|
||||
pub fn vacant_len(&self) -> usize
|
||||
{
|
||||
self.rb.vacant_len()
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,14 @@ pub mod inout;
|
||||
pub trait BlockWork
|
||||
{
|
||||
fn work(&mut self);
|
||||
fn ready(&self) -> bool;
|
||||
fn ready(&mut self) -> bool;
|
||||
}
|
||||
|
||||
pub trait Block: BlockWork
|
||||
pub trait Block
|
||||
{
|
||||
fn set_block_index(&self, index: usize);
|
||||
fn get_successors(&self) -> Vec<usize>;
|
||||
}
|
||||
|
||||
pub trait RunnableBlock: Block + BlockWork {}
|
||||
impl<T> RunnableBlock for T where T: Block + BlockWork {}
|
||||
|
||||
18
ntw_flowgraph_macros/Cargo.lock
generated
18
ntw_flowgraph_macros/Cargo.lock
generated
@ -2,6 +2,15 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ntw_flowgraph_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
@ -20,15 +29,6 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "streams_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
|
||||
@ -113,10 +113,13 @@ pub fn block_derive(item: TokenStream) -> TokenStream
|
||||
let set_index_func = set_block_index_func(&derive);
|
||||
let get_successors_func = get_successors_func(&derive);
|
||||
let struct_path = input.ident;
|
||||
let struct_where = input.generics.where_clause.clone();
|
||||
let struct_generics = input.generics;
|
||||
|
||||
//item
|
||||
quote! {
|
||||
impl Block for #struct_path
|
||||
impl #struct_generics ntw_flowgraph::Block for #struct_path #struct_generics
|
||||
#struct_where
|
||||
{
|
||||
#set_index_func
|
||||
#get_successors_func
|
||||
|
||||
38
src/main.rs
38
src/main.rs
@ -1,3 +1,9 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use ntw_dsp::Frequency;
|
||||
use ntw_dsp::blocks::map::Map;
|
||||
use ntw_dsp::blocks::nco::ComplexNco;
|
||||
use ntw_dsp::generation::Nco;
|
||||
use ntw_flowgraph::Block;
|
||||
use ntw_flowgraph::BlockWork;
|
||||
use ntw_flowgraph::graph::Graph;
|
||||
@ -39,7 +45,7 @@ impl BlockWork for VecSource
|
||||
|
||||
fn ready(&self) -> bool
|
||||
{
|
||||
self.vector.len() > 0 && self.out.rb.vacant_len() > 0
|
||||
!self.vector.is_empty() && self.out.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,15 +79,13 @@ impl BlockWork for Adder
|
||||
&& let Some(b) = self.in_b.rb.try_pop()
|
||||
&& self.out.rb.vacant_len() > 0
|
||||
{
|
||||
let _ = self.out.rb.try_push(a + b);
|
||||
let _ = self.out.try_push(a + b);
|
||||
}
|
||||
}
|
||||
|
||||
fn ready(&self) -> bool
|
||||
{
|
||||
self.in_a.rb.occupied_len() > 0
|
||||
&& self.in_b.rb.occupied_len() > 0
|
||||
&& self.out.rb.vacant_len() > 0
|
||||
self.in_a.available_len() > 0 && self.in_b.available_len() > 0 && self.out.vacant_len() > 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,13 +99,13 @@ impl Adder
|
||||
}
|
||||
|
||||
#[derive(Block)]
|
||||
pub struct PrintSink
|
||||
pub struct PrintSink<T>
|
||||
{
|
||||
#[input]
|
||||
stream: In<u32>,
|
||||
stream: In<T>,
|
||||
}
|
||||
|
||||
impl BlockWork for PrintSink
|
||||
impl<T: Display> BlockWork for PrintSink<T>
|
||||
{
|
||||
fn work(&mut self)
|
||||
{
|
||||
@ -113,13 +117,13 @@ impl BlockWork for PrintSink
|
||||
|
||||
fn ready(&self) -> bool
|
||||
{
|
||||
self.stream.rb.occupied_len() > 0
|
||||
self.stream.available_len() > 0
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintSink
|
||||
impl<T> PrintSink<T>
|
||||
{
|
||||
pub fn new(stream: In<u32>) -> PrintSink
|
||||
pub fn new(stream: In<T>) -> PrintSink<T>
|
||||
{
|
||||
PrintSink { stream }
|
||||
}
|
||||
@ -127,17 +131,15 @@ impl PrintSink
|
||||
|
||||
fn main()
|
||||
{
|
||||
let (vector_a, a) = VecSource::new((0..15).collect());
|
||||
let (vector_b, b) = VecSource::new((0..15).collect());
|
||||
let (adder, sum) = Adder::new(a, b);
|
||||
let printer = PrintSink::new(sum);
|
||||
let (nco, out) = ComplexNco::<f32>::new(Nco::new(Frequency::from_rad(0.001)));
|
||||
let (map, im) = Map::new(out, |x| x.im);
|
||||
let printer = PrintSink::new(im);
|
||||
|
||||
let mut graph = Graph::new();
|
||||
|
||||
graph.add_block(printer);
|
||||
graph.add_block(adder);
|
||||
graph.add_block(vector_a);
|
||||
graph.add_block(vector_b);
|
||||
graph.add_block(map);
|
||||
graph.add_block(nco);
|
||||
|
||||
graph.run();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user