vpp_sim/devices/
types.rs

1//! Common types and traits for device simulation components.
2
3use rand::{RngExt, rngs::StdRng};
4
5/// Contextual information passed to devices during power calculations.
6/// Includes the current timestep and optional setpoints for controllable devices.
7/// # Fields
8/// * `timestep` - Current simulation timestep
9/// * `setpoint_kw` - Optional power setpoint for controllable devices (kW)
10pub struct DeviceContext {
11    pub timestep: usize,
12    pub setpoint_kw: Option<f32>,
13}
14
15impl DeviceContext {
16    /// Creates a new DeviceContext with the given timestep and no setpoint.
17    pub fn new(timestep: usize) -> Self {
18        Self {
19            timestep,
20            setpoint_kw: None,
21        }
22    }
23
24    /// Creates a new DeviceContext with the given timestep and setpoint.
25    pub fn with_setpoint(timestep: usize, setpoint_kw: f32) -> Self {
26        Self {
27            timestep,
28            setpoint_kw: Some(setpoint_kw),
29        }
30    }
31}
32
33/// Trait defining a device that can produce or consume electricity.
34///
35/// This trait provides a common interface for all devices in the simulation,
36/// allowing them to be used interchangeably in power flow calculations.
37pub trait Device {
38    /// Returns the power value at the specified time step.
39    ///
40    /// Positive values indicate power consumption (load),
41    /// negative values indicate power generation.
42    ///
43    /// # Arguments
44    ///
45    /// * `context` - Contextual information about the device and simulation state, like:
46    ///  - `timestep`: Current simulation time step
47    ///  - `setpoint_kw`: Optional power setpoint for controllable devices
48    ///
49    /// # Returns
50    ///
51    /// Power in kilowatts (kW) at the specified time step
52    fn power_kw(&mut self, context: &DeviceContext) -> f32;
53
54    /// Returns a human-readable type name for the device.
55    fn device_type(&self) -> &'static str;
56}
57
58/// Utility function to generate Gaussian noise using Box-Muller transform.
59///
60/// # Arguments
61///
62/// * `rng` - Random number generator
63/// * `std_dev` - Standard deviation of the noise
64///
65/// # Returns
66///
67/// Random value from a Gaussian distribution with mean 0 and specified standard deviation
68pub fn gaussian_noise(rng: &mut StdRng, std_dev: f32) -> f32 {
69    if std_dev <= 0.0 {
70        return 0.0;
71    }
72
73    let u1: f32 = rng.random::<f32>().clamp(1e-6, 1.0);
74    let u2: f32 = rng.random::<f32>();
75    let z0 = (-2.0_f32 * u1.ln()).sqrt() * (2.0_f32 * std::f32::consts::PI * u2).cos();
76    z0 * std_dev
77}