relu-q15 0.1.0

ReLU en virgule fixe Q15 pour systèmes embarqués `no_std`, zéro dépendance
Documentation
  • Coverage
  • 100%
    3 out of 3 items documented3 out of 3 items with examples
  • Size
  • Source code size: 33.17 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 652.31 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 42s Average build duration of successful builds.
  • all releases: 42s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • jorgeandrecastro/relu-q15
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • jorgeandrecastro

Crates.io Docs.rs License: GPL v2

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};

// Scalaire
assert_eq!(relu_q15(-16384), 0);     // -0.5 → 0
assert_eq!(relu_q15(0),       0);    //  0.0 → 0
assert_eq!(relu_q15(16384), 16384);  //  0.5 → 0.5

// In-place sur un slice (économise la RAM du MCU)
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 _; 

// Ne pas oublier d'importer la crate 
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;
    }

    // Valeurs de tests : mélange de positif, négatif et zéro
    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];
        
        // TEST DE LA RELU 
        let output = relu_q15(input);

        // AFFICHAGE OLED 
        oled.draw_str(10, 1, b"Test RELU Q15"); 
        
        // Ligne "Entree"
        oled.draw_str(10, 3, b"In :"); 
        oled.draw_i16(60, 3, input); 

        // Ligne "Sortie"
        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; // 2 secondes pour bien lire
    }
}

#[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