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;