sac_base/lib.rs
1//! # sac-base (Signal And Control)
2//! sac-base is the base crate of its two child crates sac-control and sac-signal.
3//! This crate is still under heavy construction and not finished.
4//!
5//! ---
6//!
7//! # Idea
8//! The sac-* crates help to implement signal processing and control systems in a network based
9//! approach. Similar to Simulink as example.
10//! The project is designed for a primary usage on embedded systems and is therefore a [no_std]
11//! crate. A generic solution such as the used network based approach will never be as fast as a
12//! custom system implementation for a specific problem. But it will allow to directly and quickly
13//! implement and change systems in code instead of designing it Matlab and exporting it to C.
14//! Generation the network and building the topology is relatively expensive. Therefore the crate
15//! does all the allocations and setup before the normal operation starts.
16//! This base crate is designed in a way that allows the Signal and the Control crate to easily
17//! extend it, and allow the operations to be interchangeable between each other.
18//! Both the sac-control and the sac-signal are under construction and are not available yet.
19//!
20//! ## Base crate
21//! The base crate provides the following features:
22//! - Network description.
23//! - Base node implementation which the operations are based on.
24//! - Simple math operations such as adding, subtraction. Generally operations that will be used in both the Signal and Control crates.
25//! - Generic elements such as buffers.
26//!
27//! ## no_std
28//! The library is built with no_std. Therefore it can be used on embedded systems and while not tested, probably wasm aswell.
29//!
30//! # Example
31//! The following example, can be build by the code given below:
32//!
33//! ```rust
34//! //
35//! // +----+
36//! // | |
37//! // +--+ In +----+
38//! // | | | +-----+
39//! // +----+ +---+ |
40//! // | Add +----+-------------+
41//! // +----+ +---+ | | |
42//! // | | | +-----+ | | +-----+
43//! // +--+ In +----+ | +-----+ |
44//! // | | | | Mul +------+---+
45//! // +----+ | +-----+ | |
46//! // | +-----+ | +-----+ |
47//! // +----+ +--+ | | |
48//! // | | | Add | | |
49//! // +--+ In +----------------------+ +----+ |
50//! // | | | | |
51//! // +----+ +-----+ | |
52//! // | +-----+ |
53//! // | +-----+ |
54//! // | | | |
55//! // +--------------+ z^1 +--------------+
56//! // | |
57//! // +---- +
58//! //
59//!
60//! use sac_base::network::network::Network;
61//! use sac_base::operations::math::add::Add;
62//! use sac_base::operations::miscellaneous::buffer::Buffer;
63//! use sac_base::operations::math::multiply::Multiply;
64//! // Generate the network
65//! let mut network = Network::new();
66//! // Generate some operations
67//! let add1 = network.add_operation(Add::new());
68//! let mul1 = network.add_operation(Multiply::new());
69//! let add2 = network.add_operation(Add::new());
70//! // Add some inputs
71//! let in1 = network.add_operation(Buffer::new());
72//! let in2 = network.add_operation(Buffer::new());
73//! let in3 = network.add_operation(Buffer::new());
74//! // Connect the operations with each other
75//! network.add_connection(&in1, &add1).unwrap();
76//! network.add_connection(&in2, &add1).unwrap();
77//! network.add_connection(&add1, &add2).unwrap();
78//! network.add_connection(&in3, &add2).unwrap();
79//! network.add_connection(&add1, &mul1).unwrap();
80//! network.add_connection(&add2, &mul1).unwrap();
81//! // Insert a closed loop (Positive feedback loop)
82//! network.close_loop(&mul1, &add2);
83//! // Generate the network
84//! network.build().unwrap();
85//! // Main loop operation
86//! // Update the inputs
87//! network.set_input_sample(&in1, 5.0);
88//! network.set_input_sample(&in2, 5.0);
89//! network.set_input_sample(&in3, 5.0);
90//! // Iterate over the network
91//! network.process();
92//! let res = network.get_output(&mul1);
93//! // Update the inputs
94//! network.set_input_sample(&in1, 10.0);
95//! network.set_input_sample(&in2, 10.0);
96//! network.set_input_sample(&in3, 10.0);
97//! // Process twice to let the closed loop propagate
98//! network.process();
99//! let res = network.get_output(&mul1);
100//! ```
101//!
102//! # Extending the functionality
103//! It is likely that the library does not implement all the operations that will be needed in your application.
104//! Implementing a new operation is simple and can be added outside of the library.
105//!
106//! As example:
107//! Lets say you want to add a new operation that drops every third element.
108//! ```rust
109//! // we need a possibility to count. So we need to add a count variable to the struct which will
110//! // be boxed and moved into the node
111//! use sac_base::network::node::Node;
112//! use std::any::Any;
113//! use sac_base::network::network::Network;
114//! pub struct Third {
115//! count: usize,
116//! }
117//!
118//! // Now define the functionality
119//! impl Third {
120//!
121//! pub fn new<T>() -> Node<T>
122//! where T: Copy + Default
123//! {
124//! // Generate the storage which is the defined struct in a boxed pointer which will be
125//! // moved into the node
126//! let storage = Box::new(Third{
127//! count: 0,
128//! }) as Box<dyn Any>;
129//! Node::new(storage, |data_input: (Vec<&[T]>, usize), data_buffer: &mut Box<dyn Any>, output: &mut Vec<T>| {
130//! // Get the storage back so we can access the count variable
131//! let storage: &mut Third = data_buffer.downcast_mut::<Third>().unwrap();
132//! let (inputs, max_len) = data_input;
133//! // Start iterating over the inputs. Here we only care about one input,
134//! // so we only take 1.
135//! inputs.into_iter().take(1).into_iter().for_each(|data| {
136//! // Iterate over all the values of the input slice.
137//! data.into_iter().take(max_len).into_iter().for_each(|v| {
138//! // Modulo the count
139//! storage.count = storage.count % 3;
140//!
141//! // Now we are ready to implement the functionality.
142//! // The content of the vector will be passed into the next nodes as slice.
143//! // We are only working with one sample, so we can just put it into the
144//! // 0 position.
145//! output.clear();
146//! if storage.count == 2 {
147//! // Write default in to the vector if its the third sample.
148//! output.insert(0, T::default());
149//! } else {
150//! // Otherwise just use the normal value
151//! output.insert(0, *v);
152//! }
153//!
154//! // Increment the count and modulo it.
155//! storage.count = storage.count + 1;
156//! })
157//! })
158//! })
159//! }
160//! }
161//!
162//! let mut network: Network<f32> = Network::new();
163//!
164//! // Insert the new node into the network
165//! let third = network.add_operation(Third::new());
166//!
167//! network.build();
168//!
169//! network.set_input_slice(&third, &[1.0, 2.0, 3.0][..]);
170//!
171//! network.process();
172//! let res = network.get_output(&third).unwrap();
173//!
174//! assert_eq!(res, [1.0, 2.0, 3.0]);
175//! ```
176//!
177//! # Outlook
178//! - Base crate:
179//! - Operations:
180//! - To chunk and from chuck operations
181//! - Far future:
182//! - Static operation
183//! - Signal processing:
184//! - Checkout https://gitlab.com/signal-and-control/sac-signal
185//! - Control:
186//! - Checkout https://gitlab.com/signal-and-control/sac-control
187
188#![no_std]
189
190#[cfg(test)]
191#[macro_use]
192extern crate std;
193
194#[cfg(test)]
195extern crate assert_approx_eq;
196
197pub mod operations;
198pub mod network;
199pub mod helper;
200
201extern crate alloc;
202extern crate graphlib;
203extern crate num;