6个版本
0.0.7 | 2020年5月10日 |
---|---|
0.0.6 | 2020年5月5日 |
0.0.5 | 2020年4月26日 |
0.0.3 | 2020年3月18日 |
#490 in 嵌入式开发
83KB
1.5K SLoC
sac-base (信号与控制)
sac-base 是 sac-control 和 sac-signal 两个子crate的基础crate。这个crate仍在大力开发中,尚未完成。
想法
sac-* crate 帮助以网络为基础的方法实现信号处理和控制系统。类似于Simulink等示例。该项目主要针对嵌入式系统使用,因此是一个 [no_std] crate。与针对特定问题定制的系统实现相比,通用的网络方法永远不会那么快。但它将允许直接快速地在代码中实现和更改系统,而不是在Matlab中设计并导出到C。生成网络和构建拓扑相对昂贵。因此,crate在正常操作开始之前执行所有的分配和设置。这个基础crate的设计方式允许信号和控制crate轻松扩展它,并允许操作之间可以互换。sac-control 和 sac-signal 都在建设中,尚未提供。
基础crate
基础crate提供以下功能
- 网络描述。
- 基于基础节点的实现,操作基于此。
- 简单的数学运算,如加法、减法。通常在信号和控制crate中都会使用到的操作。
- 通用元素,如缓冲区。
no_std
库是用 no_std 构建的。因此,它可以在嵌入式系统上使用,虽然没有进行测试,但也可以在wasm上使用。
示例
以下示例可以通过以下代码构建
//
// +----+
// | |
// +--+ In +----+
// | | | +-----+
// +----+ +---+ |
// | Add +----+-------------+
// +----+ +---+ | | |
// | | | +-----+ | | +-----+
// +--+ In +----+ | +-----+ |
// | | | | Mul +------+---+
// +----+ | +-----+ | |
// | +-----+ | +-----+ |
// +----+ +--+ | | |
// | | | Add | | |
// +--+ In +----------------------+ +----+ |
// | | | | |
// +----+ +-----+ | |
// | +-----+ |
// | +-----+ |
// | | | |
// +--------------+ z^1 +--------------+
// | |
// +---- +
//
use sac_base::network::network::Network;
use sac_base::operations::math::add::Add;
use sac_base::operations::miscellaneous::buffer::Buffer;
use sac_base::operations::math::multiply::Multiply;
// Generate the network
let mut network = Network::new();
// Generate some operations
let add1 = network.add_operation(Add::new());
let mul1 = network.add_operation(Multiply::new());
let add2 = network.add_operation(Add::new());
// Add some inputs
let in1 = network.add_input(Buffer::new());
let in2 = network.add_input(Buffer::new());
let in3 = network.add_input(Buffer::new());
// Connect the operations with each other
network.add_connection(&in1, &add1).unwrap();
network.add_connection(&in2, &add1).unwrap();
network.add_connection(&add1, &add2).unwrap();
network.add_connection(&in3, &add2).unwrap();
network.add_connection(&add1, &mul1).unwrap();
network.add_connection(&add2, &mul1).unwrap();
// Register the multiplication as an output
network.as_output(&mul1);
// Insert a closed loop (Positive feedback loop)
network.close_loop(&mul1, &add2);
// Generate the network
network.build();
// Main loop operation
// Update the inputs
network.set_inputs(| index | {
return 5.0;
});
// Iterate over the network
network.process();
let res = network.get_outputs();
// Update the inputs
network.set_inputs(| index | {
return 10.0;
});
// Process twice to let the closed loop propagate
network.process();
let res = network.get_outputs();
扩展功能
很可能库没有实现您应用程序中需要的所有操作。实现一个新操作很简单,可以添加到库外部。
例如:假设您想添加一个新操作,该操作会丢弃每第三个元素。
// we need a possibility to count. So we need to add a count variable to the struct which will
// be boxed and moved into the node
use sac_base::network::node::Node;
use std::any::Any;
use sac_base::network::network::Network;
pub struct Third {
count: usize,
}
// Now define the functionality
impl Third {
pub fn new<T>() -> Node<T>
where T: Copy + Default
{
// Generate the storage which is the defined struct in a boxed pointer which will be
// moved into the node
let storage = Box::new(Third{
count: 0,
}) as Box<dyn Any>;
Node::new(storage, |data_input: (Vec<&[T]>, usize), data_buffer: &mut Box<dyn Any>, output: &mut Vec<T>| {
// Get the storage back so we can access the count variable
let storage: &mut Third = data_buffer.downcast_mut::<Third>().unwrap();
let (inputs, max_len) = data_input;
// Start iterating over the inputs. Here we only care about one input,
// so we only take 1.
inputs.into_iter().take(1).into_iter().for_each(|data| {
// Iterate over all the values of the input slice.
data.into_iter().take(max_len).into_iter().for_each(|v| {
// Modulo the count
storage.count = storage.count % 3;
// Now we are ready to implement the functionality.
// The content of the vector will be passed into the next nodes as slice.
// We are only working with one sample, so we can just put it into the
// 0 position.
output.clear();
if storage.count == 2 {
// Write default in to the vector if its the third sample.
output.insert(0, T::default());
} else {
// Otherwise just use the normal value
output.insert(0, *v);
}
// Increment the count and modulo it.
storage.count = storage.count + 1;
})
})
})
}
}
let mut network: Network<f32> = Network::new();
// Insert the new node into the network
let third = network.add_operation(Third::new());
network.build();
network.set_input_slice(&third, &[1.0, 2.0, 3.0][..]);
network.process();
let res = network.get_output(&third).unwrap();
assert_eq!(res, [1.0, 2.0, 3.0]);
展望
- 基础crate
- 操作
- 块和从块操作
- 长远来看
- 静态操作(具有无堆栈向量功能)
- 操作
- 信号处理
- 控制
依赖项
约2MB
约36K SLoC