From 2115c31f0c1a8900cd8dbe4dd2d34bd5f16905a5 Mon Sep 17 00:00:00 2001 From: Justin Worthe Date: Tue, 27 Dec 2016 18:27:18 +0200 Subject: Added in addition of sinusoids with the same phase --- src/sinusoid.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 11 deletions(-) diff --git a/src/sinusoid.rs b/src/sinusoid.rs index fe8b3ad..4bbfcc3 100644 --- a/src/sinusoid.rs +++ b/src/sinusoid.rs @@ -1,5 +1,6 @@ use std::cmp::{PartialOrd}; -use ::num_traits::{Trig, ArithmeticOps, FractionOps}; +use ::num_traits::{Trig, Pow, ArithmeticOps, FractionOps}; +use ::complex::Complex; /// A data structure representing a sinusoid. AKA the sin or cos functions. /// @@ -7,6 +8,7 @@ use ::num_traits::{Trig, ArithmeticOps, FractionOps}; /// /// The number type is generic, but realistically it's only useful for /// floats. +#[derive(Debug, Clone, PartialEq)] pub struct Sinusoid { amplitude: T, frequency: T, @@ -31,12 +33,86 @@ impl Sinusoid where T: FractionOps + Copy { /// use std::f32; /// /// let sinusoid = Sinusoid::new(1.0 as f32, 0.5, 0.0); - /// assert!((sinusoid.period()-2.0) < f32::EPSILON); + /// assert!((sinusoid.period()-2.0).abs() < f32::EPSILON); /// ``` pub fn period(&self) -> T { self.frequency.recip() } } + +#[derive(Debug, PartialEq)] +pub enum AddSinusoidError { + DifferentFrequency +} + +impl Sinusoid where T: Trig + Pow + ArithmeticOps + Copy { + /// Converts the sinusoid to phaser form + /// + /// This discards the frequency. Take care to only compare phasers + /// that had the same frequency before their conversion. + /// + /// ``` + /// use worthe_signals::sinusoid::Sinusoid; + /// use worthe_signals::complex::Complex; + /// use std::f32; + + /// let pure_real = Sinusoid::new(1.0 as f32, 0.5, 0.0); + /// let pure_real_phasor = pure_real.to_phaser(); + /// assert!((pure_real_phasor.real - 1.0).abs() < f32::EPSILON); + /// assert!((pure_real_phasor.imag - 0.0).abs() < f32::EPSILON); + /// + /// let pure_imag = Sinusoid::new(1.0 as f32, 2.0, -f32::consts::FRAC_PI_2); + /// let pure_imag_phasor = pure_imag.to_phaser(); + /// assert!((pure_imag_phasor.real - 0.0).abs() < f32::EPSILON); + /// assert!((pure_imag_phasor.imag + 1.0).abs() < f32::EPSILON); + /// ``` + pub fn to_phaser(self) -> Complex { + Complex::from_polar(self.amplitude, self.phase) + } +} + +impl Sinusoid where T: Trig + Pow + ArithmeticOps + PartialEq + Copy { + /// Adds two sinusoids together into one sinusoid. + /// + /// # Errors + /// + /// This can only be done if the two sinusoids have the same + /// frequency. + /// + /// ``` + /// use worthe_signals::sinusoid::{Sinusoid, AddSinusoidError}; + /// + /// let sin1 = Sinusoid::new(1.0 as f32, 0.5, 0.0); + /// let sin2 = Sinusoid::new(1.0 as f32, 2.0, 0.0); + /// assert_eq!(Err(AddSinusoidError::DifferentFrequency), sin1.add(sin2)); + /// ``` + /// + /// # Examples + /// + /// ``` + /// use worthe_signals::sinusoid::{Sinusoid, AddSinusoidError}; + /// use std::f32; + /// + /// let sin1 = Sinusoid::new(-3.0 as f32, 1.0, 0.0); + /// let sin2 = Sinusoid::new(4.0 as f32, 1.0, -f32::consts::FRAC_PI_2); + /// assert_eq!(Ok(Sinusoid::new(5.0, 1.0, -2.21429743558818100603413092035707408014009529080286529335)), sin1.add(sin2)); + /// ``` + pub fn add(self, other: Sinusoid) -> Result { + if self.frequency != other.frequency { + Err(AddSinusoidError::DifferentFrequency) + } + else { + let frequency = self.frequency; + let self_phaser = self.to_phaser(); + let other_phaser = other.to_phaser(); + let combined = self_phaser + other_phaser; + let (amplitude, phase) = combined.to_polar(); + Ok(Sinusoid::new(amplitude, frequency, phase)) + } + + } +} + impl Sinusoid where T: FractionOps + ArithmeticOps + Trig + Copy { /// Frequency can be considered in terms of the signal's number of /// repetitions per second (referred to just as the frequency), or @@ -60,11 +136,11 @@ impl Sinusoid where T: FractionOps + ArithmeticOps + Trig + Copy { /// use std::f32; /// /// let sinusoid = Sinusoid::new(1.0 as f32, 1.0, -f32::consts::FRAC_PI_2); //AKA sin - /// assert!((sinusoid.sample(0.0)-0.0) < f32::EPSILON); - /// assert!((sinusoid.sample(0.25)-1.0) < f32::EPSILON); - /// assert!((sinusoid.sample(0.5)-0.0) < f32::EPSILON); - /// assert!((sinusoid.sample(0.75)+1.0) < f32::EPSILON); - /// assert!((sinusoid.sample(1.0)-0.0) < f32::EPSILON); + /// assert!((sinusoid.sample(0.0)-0.0).abs() < f32::EPSILON); + /// assert!((sinusoid.sample(0.25)-1.0).abs() < f32::EPSILON); + /// assert!((sinusoid.sample(0.5)-0.0).abs() < f32::EPSILON); + /// assert!((sinusoid.sample(0.75)+1.0).abs() < f32::EPSILON); + /// assert!((sinusoid.sample(1.0)-0.0).abs() < f32::EPSILON); /// ``` pub fn sample(&self, t: T) -> T { (self.radial_frequency()*(t%self.period()) + self.phase).cos() * self.amplitude @@ -83,10 +159,10 @@ impl Sinusoid where T: FractionOps + ArithmeticOps + From + Trig + Co /// let samples = sinusoid.sample_range(0.0, 100.0, 4.0); /// assert_eq!(samples.len(), 400); /// for i in (0..100).map(|i| i*4) { - /// assert!((samples[i+0]-0.0) < f32::EPSILON, "Sample {} was {}", i+0, samples[i+0]); - /// assert!((samples[i+1]-1.0) < f32::EPSILON, "Sample {} was {}", i+1, samples[i+1]); - /// assert!((samples[i+2]-0.0) < f32::EPSILON, "Sample {} was {}", i+2, samples[i+2]); - /// assert!((samples[i+3]+1.0) < f32::EPSILON, "Sample {} was {}", i+3, samples[i+3]); + /// assert!((samples[i+0]-0.0).abs() < f32::EPSILON, "Sample {} was {}", i+0, samples[i+0]); + /// assert!((samples[i+1]-1.0).abs() < f32::EPSILON, "Sample {} was {}", i+1, samples[i+1]); + /// assert!((samples[i+2]-0.0).abs() < f32::EPSILON, "Sample {} was {}", i+2, samples[i+2]); + /// assert!((samples[i+3]+1.0).abs() < f32::EPSILON, "Sample {} was {}", i+3, samples[i+3]); /// } /// ``` pub fn sample_range(&self, start: T, end: T, sample_rate: T) -> Vec { @@ -105,9 +181,11 @@ impl Sinusoid where T: FractionOps + ArithmeticOps + From + Trig + Co } } +/* #[cfg(test)] mod tests { use super::*; use std::f32; } +*/ -- cgit v1.2.3