#![allow(dead_code)]
use core::f32::consts::PI;
const VPEAK: f32 = 325.26915;
const IPEAK: f32 = 70.71068;
const IPHASE: f32 = -18.2;
const SAMPLES_OFFSET: f32 = 12.0;
const NOISE_FREQ: f32 = 6000.0;
const NOISE_VPEAK_PERCENT: f32 = 0.0;
const NOISE_IPEAK_PERCENT: f32 = 0.005;
const NOISE_RANDOM_PERCENT: f32 = 0.001;
const FS: f32 = 8000.0;
const F: f32 = 49.98;
const N_SAMPLES: usize = 160;
pub const ADC_FULL_SCALE_COUNTS: f32 = 8388608.0;
pub const VIN_TO_COUNTS: f32 = (ADC_FULL_SCALE_COUNTS / 1.2) / 410.09;
pub const AMPS_TO_COUNTS: f32 = (ADC_FULL_SCALE_COUNTS / 1.2) / (2000.0 / 100.0);
pub const ENABLE_THREE_PHASE: bool = true;
const ENABLE_HARMONICS: bool = true;
const VOLTAGE_HARMONICS: [(f32, f32); 11] = [
(3.0, 0.015), (5.0, 0.012), (7.0, 0.008), (9.0, 0.003), (11.0, 0.002), (13.0, 0.001), (15.0, 0.001), (17.0, 0.0005), (19.0, 0.0005), (21.0, 0.0002), (23.0, 0.0001), ];
const CURRENT_HARMONICS: [(f32, f32); 11] = [
(3.0, 0.065), (5.0, 0.045), (7.0, 0.025), (9.0, 0.012), (11.0, 0.008), (13.0, 0.005), (15.0, 0.003), (17.0, 0.002), (19.0, 0.001), (21.0, 0.001), (23.0, 0.0005), ];
#[cfg(not(feature = "rand"))]
struct SimpleRng(u32);
#[cfg(not(feature = "rand"))]
impl SimpleRng {
fn next_f32(&mut self) -> f32 {
self.0 = self.0.wrapping_mul(1103515245).wrapping_add(12345);
(self.0 >> 8) as f32 / 16777216.0
}
}
fn voltage(v: f32) -> f32 {
v * VIN_TO_COUNTS
}
fn current(i: f32) -> f32 {
i * AMPS_TO_COUNTS
}
fn offset(deg: f32) -> f32 {
deg * 2.0 * PI / 360.0
}
fn angle_rad(phase_deg: f32, i: usize) -> f32 {
offset(phase_deg) + 2.0 * PI * F / FS * i as f32
}
fn gen_one_signal(
phase_deg: f32,
peak: f32,
is_voltage: bool,
noise: &[f32],
noise_mean: f32,
noise_max: f32,
) -> alloc::vec::Vec<f32> {
let mut sig: alloc::vec::Vec<f32> = (0..N_SAMPLES)
.map(|i| {
let a = angle_rad(phase_deg, i);
if is_voltage {
peak * crate::math::sin(a)
} else {
peak * crate::math::sin(a + offset(IPHASE))
}
})
.collect();
if ENABLE_HARMONICS {
let harmonics = if is_voltage {
&VOLTAGE_HARMONICS[..]
} else {
&CURRENT_HARMONICS[..]
};
for (harm_order, perc) in harmonics {
let freq = F * harm_order;
let harm_peak = peak * perc;
for (i, s) in sig.iter_mut().enumerate() {
let harm_angle = offset(phase_deg) + 2.0 * PI * freq / FS * i as f32;
if is_voltage {
*s += harm_peak * crate::math::sin(harm_angle);
} else {
*s += harm_peak * crate::math::sin(harm_angle + offset(IPHASE));
}
}
}
}
if NOISE_VPEAK_PERCENT > 0.0 && is_voltage {
for (i, s) in sig.iter_mut().enumerate() {
*s += peak
* (NOISE_VPEAK_PERCENT
* crate::math::sin(offset(0.0) + 2.0 * PI * NOISE_FREQ / FS * i as f32));
}
}
if NOISE_IPEAK_PERCENT > 0.0 && !is_voltage {
for (i, s) in sig.iter_mut().enumerate() {
*s += peak
* (NOISE_IPEAK_PERCENT
* crate::math::sin(offset(0.0) + 2.0 * PI * NOISE_FREQ / FS * i as f32));
}
}
if NOISE_RANDOM_PERCENT > 0.0 {
for i in 0..N_SAMPLES {
sig[i] += peak * (noise[i] - noise_mean) / noise_max * NOISE_RANDOM_PERCENT;
}
}
sig
}
fn gen_noise() -> (alloc::vec::Vec<f32>, f32, f32) {
if NOISE_RANDOM_PERCENT > 0.0 {
#[cfg(feature = "rand")]
{
let noise: alloc::vec::Vec<f32> =
(0..N_SAMPLES).map(|_| rand::random::<f32>()).collect();
let noise_mean = noise.iter().copied().sum::<f32>() / noise.len() as f32;
let noise_max = noise.iter().copied().fold(f32::NEG_INFINITY, f32::max);
(noise, noise_mean, noise_max)
}
#[cfg(not(feature = "rand"))]
{
let mut rng = SimpleRng(42);
let noise: alloc::vec::Vec<f32> = (0..N_SAMPLES).map(|_| rng.next_f32()).collect();
let noise_mean = noise.iter().copied().sum::<f32>() / noise.len() as f32;
let noise_max = noise.iter().copied().fold(f32::NEG_INFINITY, f32::max);
(noise, noise_mean, noise_max)
}
} else {
(alloc::vec::Vec::new(), 0.0, 1.0)
}
}
fn to_i32_vec(v: alloc::vec::Vec<f32>) -> alloc::vec::Vec<i32> {
v.into_iter()
.map(|s| crate::math::trunc(s + SAMPLES_OFFSET) as i32)
.collect()
}
pub fn generate_signals_monophase() -> alloc::vec::Vec<alloc::vec::Vec<i32>> {
let (noise, noise_mean, noise_max) = gen_noise();
let v_peak = voltage(VPEAK);
let i_peak = current(IPEAK);
let v = gen_one_signal(0.0, v_peak, true, &noise, noise_mean, noise_max);
let i = gen_one_signal(0.0, i_peak, false, &noise, noise_mean, noise_max);
alloc::vec![to_i32_vec(v), to_i32_vec(i)]
}
pub fn generate_signals() -> alloc::vec::Vec<alloc::vec::Vec<i32>> {
if !ENABLE_THREE_PHASE {
return generate_signals_monophase();
}
let (noise, noise_mean, noise_max) = gen_noise();
let v_peak = voltage(VPEAK);
let i_peak = current(IPEAK);
let v_a = gen_one_signal(0.0, v_peak, true, &noise, noise_mean, noise_max);
let i_a = gen_one_signal(0.0, i_peak, false, &noise, noise_mean, noise_max);
let v_b = gen_one_signal(-120.0, v_peak, true, &noise, noise_mean, noise_max);
let i_b = gen_one_signal(-120.0, i_peak, false, &noise, noise_mean, noise_max);
let v_c = gen_one_signal(120.0, v_peak, true, &noise, noise_mean, noise_max);
let i_c = gen_one_signal(120.0, i_peak, false, &noise, noise_mean, noise_max);
let unused = alloc::vec![0.0; N_SAMPLES];
let i_n: alloc::vec::Vec<f32> = (0..N_SAMPLES)
.map(|i| -(i_a[i] + i_b[i] + i_c[i]))
.collect();
alloc::vec![
to_i32_vec(v_a),
to_i32_vec(i_a),
to_i32_vec(v_b),
to_i32_vec(i_b),
to_i32_vec(v_c),
to_i32_vec(i_c),
to_i32_vec(i_n),
to_i32_vec(unused)
]
}