use core::f64;
#[cfg(feature = "python")]
use pyo3::prelude::*;
use super::*;
use crate::{calc_config, calc_input_names, calc_output_names, py_json_methods};
#[cfg_attr(feature = "python", pyclass)]
#[derive(Serialize, Deserialize, Default, Debug)]
pub struct Sin {
period_s: f64,
offset_s: f64,
low: f64,
high: f64,
save_outputs: bool,
#[serde(default)]
output_unit: Option<String>,
#[serde(skip)]
output_index: usize,
#[serde(skip)]
rad_per_cycle: f64,
#[serde(skip)]
angle_rad: f64,
#[serde(skip)]
scale: f64,
}
impl Sin {
pub fn new(period_s: f64, offset_s: f64, low: f64, high: f64, save_outputs: bool) -> Box<Self> {
let output_index = usize::MAX;
let rad_per_cycle = 0.0;
let angle_rad = offset_s * 2.0 * f64::consts::PI / period_s; let (high, low) = (high.max(low), low.min(high));
let scale = (high - low) / 2.0;
Box::new(Self {
period_s,
offset_s,
low,
high,
save_outputs,
output_unit: None,
output_index,
rad_per_cycle,
angle_rad,
scale,
})
}
pub fn with_output_unit(mut self: Box<Self>, unit: impl Into<String>) -> Box<Self> {
self.output_unit = Some(unit.into());
self
}
}
py_json_methods!(
Sin,
Calc,
#[new]
#[pyo3(signature = (period_s, offset_s, low, high, save_outputs, output_unit = None))]
fn py_new(
period_s: f64,
offset_s: f64,
low: f64,
high: f64,
save_outputs: bool,
output_unit: Option<String>,
) -> Self {
let mut calc = Self::new(period_s, offset_s, low, high, save_outputs);
calc.output_unit = output_unit;
*calc
}
);
#[typetag::serde]
impl Calc for Sin {
fn init(
&mut self,
ctx: ControllerCtx,
_input_indices: Vec<usize>,
output_range: Range<usize>,
) -> Result<(), String> {
self.output_index = output_range.clone().next().unwrap();
self.rad_per_cycle = (ctx.dt_ns as f64 / 1e9) * 2.0 * f64::consts::PI / self.period_s;
Ok(())
}
fn terminate(&mut self) -> Result<(), String> {
self.output_index = usize::MAX;
self.rad_per_cycle = 0.0;
self.angle_rad = 0.0;
self.scale = 0.0;
Ok(())
}
fn eval(&mut self, tape: &mut [f64]) -> Result<(), String> {
self.angle_rad += self.rad_per_cycle;
let y = (self.angle_rad.sin() + 1.0) * self.scale + self.low;
tape[self.output_index] = y;
Ok(())
}
fn get_input_map(&self) -> BTreeMap<CalcInputName, FieldName> {
BTreeMap::new()
}
fn update_input_map(&mut self, _field: &str, _source: &str) -> Result<(), String> {
Ok(())
}
fn get_output_units(&self) -> Vec<Option<String>> {
vec![self.output_unit.clone()]
}
calc_config!(period_s, offset_s, low, high);
calc_input_names!();
calc_output_names!(y);
}