
relu-q15
Fonction d'activation ReLU (max(0, x)) en virgule fixe Q15 pour systèmes embarqués no_std, testé sur pico 2040 zero.
Caractéristiques
#![no_std] : aucune dépendance à la bibliothèque standard.
- Arithmétique entière pure:pas de flottants, pas de
libm.
- Compatible RP2040 (Cortex-M0+) et RP2350 (Cortex-M33).
- Temps d'exécution constant (déterministe):idéal pour les noyaux temps réel.
- Zéro allocation dynamique:traitement in-place.
- #![forbid(unsafe_code)]:pour une safety garantie par Rust .
Format Q15
En Q15, un i16 représente un réel dans [-1.0, 1.0[ :
valeur_réelle = valeur_i16 / 32768.0
i16 |
Valeur réelle |
-32768 |
-1.0 |
0 |
0.0 |
16384 |
0.5 |
32767 |
≈ 1.0 |
Utilisation
[dependencies]
relu-q15 = "0.1.0"
use relu_q15::{relu_q15, relu_slice_q15};
assert_eq!(relu_q15(-16384), 0); assert_eq!(relu_q15(0), 0); assert_eq!(relu_q15(16384), 16384);
let mut buf = [-32768i16, -1, 0, 1, 32767];
relu_slice_q15(&mut buf);
assert_eq!(buf, [0, 0, 0, 1, 32767]);
Cas limites garantis
| Entrée |
Sortie |
Raison |
i16::MIN |
0 |
plus petite valeur Q15 |
-1 |
0 |
négatif |
0 |
0 |
zéro n'est pas positif |
1 |
1 |
identité |
i16::MAX |
32767 |
plus grande valeur Q15 |
Exemple Sur pico 2040 zero Embassy , Oled : embassy-ssd1306 = "0.2.3"
#![no_std]
#![no_main]
use cortex_m_rt as _;
use embassy_executor::Spawner;
use embassy_rp::i2c::{Config as I2cConfig, I2c, Async};
use embassy_time::Timer;
use {panic_halt as _, embassy_rp as _};
use embassy_ssd1306::Ssd1306;
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice;
use embassy_rp::bind_interrupts;
use embassy_rp::peripherals::I2C0;
use rp2040_linker as _;
use relu_q15::relu_q15;
bind_interrupts!(struct Irqs {
I2C0_IRQ => embassy_rp::i2c::InterruptHandler<I2C0>;
});
#[embassy_executor::task]
async fn system_task(
mut oled: Ssd1306<I2cDevice<'static, NoopRawMutex, I2c<'static, I2C0, Async>>>
) {
if let Ok(_) = oled.init().await {
oled.clear();
oled.draw_rect(0, 0, 127, 63, true);
let _ = oled.flush().await;
Timer::after_millis(500).await;
}
let test_values: [i16; 4] = [-16384, 8192, -32768, 32767];
let mut idx = 0;
loop {
oled.clear();
oled.draw_rect(0, 0, 127, 63, true);
let input = test_values[idx];
let output = relu_q15(input);
oled.draw_str(10, 1, b"Test RELU Q15");
oled.draw_str(10, 3, b"In :");
oled.draw_i16(60, 3, input);
oled.draw_str(10, 5, b"Out:");
oled.draw_i16(60, 5, output);
let _ = oled.flush().await;
idx = (idx + 1) % test_values.len();
Timer::after_secs(2).await; }
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_rp::init(embassy_rp::config::Config::default());
let mut i2c_config = I2cConfig::default();
i2c_config.frequency = 400_000;
let i2c_bus = I2c::new_async(p.I2C0, p.PIN_9, p.PIN_8, Irqs, i2c_config);
static I2C_BUS: static_cell::StaticCell<Mutex<NoopRawMutex, I2c<'static, I2C0, Async>>> = static_cell::StaticCell::new();
let i2c_mutex = I2C_BUS.init(Mutex::new(i2c_bus));
let i2c_dev_oled = I2cDevice::new(i2c_mutex);
let oled = Ssd1306::new(i2c_dev_oled, 0x3C);
spawner.spawn(system_task(oled)).unwrap();
}
Licence
GPL-2.0-or-later : voir LICENSE.
🦅 À propos
Développé et testé par Jorge Andre Castro