diff --git a/simulator/src/integrated/send_messages.rs b/simulator/src/integrated/send_messages.rs index 125d1fbf7..8c92d4c3d 100644 --- a/simulator/src/integrated/send_messages.rs +++ b/simulator/src/integrated/send_messages.rs @@ -8,6 +8,7 @@ use crate::{ EventList, Trace, run_messages::{ SendAlarm, SendRunLogData, SendRunStart, SendRunStop, SendSampleEnvLog, + SendSampleEnvLogValues, }, utils::JsonValueError, }, @@ -226,10 +227,17 @@ pub(crate) fn send_se_log_command( }) .map(|timestamps| fbb.create_vector(×tamps)); + let values = match &sample_env.values { + SendSampleEnvLogValues::Literal(items) => items.clone(), + SendSampleEnvLogValues::FromNoise { length, noise } => { + sample_environment::generate_value(*length, noise)? + } + }; + let values = Some(sample_environment::make_value( &mut fbb, values_type, - &sample_env.values, + &values, )); let se_log_args = se00_SampleEnvironmentDataArgs { diff --git a/simulator/src/integrated/simulation_elements/noise.rs b/simulator/src/integrated/simulation_elements/noise.rs index cb01de143..853034492 100644 --- a/simulator/src/integrated/simulation_elements/noise.rs +++ b/simulator/src/integrated/simulation_elements/noise.rs @@ -1,5 +1,7 @@ use std::collections::VecDeque; +use crate::integrated::simulation_elements::FloatRandomDistribution; + use super::{Interval, NumExpression, utils::JsonValueError}; use chrono::Utc; use digital_muon_common::Time; @@ -24,6 +26,13 @@ impl NoiseSource { pub(crate) fn sample(&self, time: Time, frame_index: usize) -> Result { if self.bounds.is_in(time, frame_index)? { match &self.attributes { + NoiseAttributes::Bernoulli { probability, value } => { + if rand::random_bool(probability.value(frame_index)?) { + value.sample(frame_index) + } else { + Ok(0.0) + } + } NoiseAttributes::Uniform(Interval { min, max }) => { let val = (max.value(frame_index)? - min.value(frame_index)?) * rand::random::() @@ -47,6 +56,10 @@ impl NoiseSource { #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "kebab-case", tag = "noise-type")] pub(crate) enum NoiseAttributes { + Bernoulli { + probability: NumExpression, + value: FloatRandomDistribution, + }, Uniform(Interval>), Gaussian { mean: NumExpression, diff --git a/simulator/src/integrated/simulation_elements/run_messages.rs b/simulator/src/integrated/simulation_elements/run_messages.rs index adf6c39d1..833b8c169 100644 --- a/simulator/src/integrated/simulation_elements/run_messages.rs +++ b/simulator/src/integrated/simulation_elements/run_messages.rs @@ -1,5 +1,5 @@ use crate::{ - integrated::simulation_elements::utils::TextConstant, + integrated::simulation_elements::{noise::NoiseSource, utils::TextConstant}, runs::{ alarm::SeverityLevel, runlog::ValueType, @@ -32,7 +32,7 @@ pub(crate) struct SendRunLogData { } #[derive(Clone, Debug, Deserialize)] -#[serde(rename_all = "kebab-case", tag = "run-command")] +#[serde(rename_all = "kebab-case")] pub(crate) struct SendSampleEnvLog { pub(crate) name: TextConstant, pub(crate) channel: Option, @@ -40,8 +40,18 @@ pub(crate) struct SendSampleEnvLog { pub(crate) values_type: ValuesType, pub(crate) message_counter: Option, pub(crate) location: LocationType, - pub(crate) values: Vec, pub(crate) timestamps: Option>>, + pub(crate) values: SendSampleEnvLogValues, +} + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub(crate) enum SendSampleEnvLogValues { + Literal(Vec), + FromNoise { + length: usize, + noise: Vec, + }, } #[derive(Clone, Debug, Deserialize)] diff --git a/simulator/src/integrated/simulation_engine/actions.rs b/simulator/src/integrated/simulation_engine/actions.rs index af40bd06c..88dcad08d 100644 --- a/simulator/src/integrated/simulation_engine/actions.rs +++ b/simulator/src/integrated/simulation_engine/actions.rs @@ -95,6 +95,8 @@ pub(crate) enum Action { // FrameLoop(Loop), // + LogLoop(Loop), + // SetTimestamp(Timestamp), SetVetoFlags(u16), SetPeriod(u64), @@ -137,3 +139,13 @@ pub(crate) enum DigitiserAction { GenerateTrace(GenerateTrace), GenerateEventList(GenerateEventList), } + +#[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub(crate) enum LogAction { + Comment(#[allow(unused)] String), + SendRunLogData(SendRunLogData), + SendSampleEnvLog(SendSampleEnvLog), + SendAlarm(SendAlarm), + SetTimestamp(Timestamp), +} diff --git a/simulator/src/integrated/simulation_engine/engine.rs b/simulator/src/integrated/simulation_engine/engine.rs index fa38f0d2b..6da170c3f 100644 --- a/simulator/src/integrated/simulation_engine/engine.rs +++ b/simulator/src/integrated/simulation_engine/engine.rs @@ -11,8 +11,8 @@ use crate::integrated::{ utils::JsonValueError, }, simulation_engine::actions::{ - Action, DigitiserAction, FrameAction, GenerateEventList, GenerateTrace, Timestamp, - TracingEvent, TracingLevel, + Action, DigitiserAction, FrameAction, GenerateEventList, GenerateTrace, LogAction, + Timestamp, TracingEvent, TracingLevel, }, }; use chrono::{DateTime, TimeDelta, Utc}; @@ -255,6 +255,12 @@ pub(crate) fn run_schedule(engine: &mut SimulationEngine) -> Result<(), Simulati run_frame(engine, frame_loop.schedule.as_slice())?; } } + Action::LogLoop(log_loop) => { + for index in log_loop.start.value()?..=log_loop.end.value()? { + engine.state.metadata.frame_number = index as FrameNumber; + run_logloop_schedule(engine, log_loop.schedule.as_slice())?; + } + } Action::Comment(_) => (), } } @@ -391,3 +397,40 @@ pub(crate) fn run_digitiser( } Ok(()) } + +#[tracing::instrument(skip_all, level = "debug" + fields( + index = engine.state.metadata.frame_number, + num_actions = log_actions.len() + ) + err(level = "error") +)] +pub(crate) fn run_logloop_schedule( + engine: &mut SimulationEngine, + log_actions: &[LogAction], +) -> Result<(), SimulationEngineError> { + for action in log_actions { + match action { + LogAction::SendRunLogData(run_log_data) => send_run_log_command( + &mut engine.externals, + &engine.state.metadata.timestamp, + run_log_data, + )?, + LogAction::SendSampleEnvLog(sample_env_log) => send_se_log_command( + &mut engine.externals, + &engine.state.metadata.timestamp, + sample_env_log, + )?, + LogAction::SendAlarm(alarm) => { + send_alarm_command( + &mut engine.externals, + &engine.state.metadata.timestamp, + alarm, + )?; + } + LogAction::SetTimestamp(timestamp) => set_timestamp(engine, timestamp)?, + LogAction::Comment(_) => (), + } + } + Ok(()) +} diff --git a/simulator/src/runs/sample_environment.rs b/simulator/src/runs/sample_environment.rs index 961819acb..d0e13d66d 100644 --- a/simulator/src/runs/sample_environment.rs +++ b/simulator/src/runs/sample_environment.rs @@ -1,4 +1,5 @@ use clap::ValueEnum; +use digital_muon_common::Time; use digital_muon_streaming_types::{ ecs_se00_data_generated::{ DoubleArray, DoubleArrayArgs, FloatArray, FloatArrayArgs, Int8Array, Int8ArrayArgs, @@ -11,6 +12,8 @@ use digital_muon_streaming_types::{ use serde::Deserialize; use std::str::FromStr; +use crate::integrated::simulation_elements::{noise::NoiseSource, utils::JsonValueError}; + #[derive(Clone, Debug, Deserialize, ValueEnum)] #[serde(rename_all = "kebab-case")] pub(crate) enum ValuesType { @@ -84,6 +87,21 @@ where ) } +pub(crate) fn generate_value( + length: usize, + noise_sources: &[NoiseSource], +) -> Result, JsonValueError> { + (0..length) + .map(|time| { + noise_sources + .iter() + .map(|ns| ns.sample(time as Time, 0)) + .sum::>() + }) + .map(|val| val.map(|val| val.to_string())) + .collect::, _>>() +} + pub(crate) fn make_value( fbb: &mut FlatBufferBuilder, value_type: ValueUnion,