emd 0.1.3.0 → 0.1.4.0
raw patch · 5 files changed
+131/−11 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Numeric.HHT: dominantFreq :: forall v n a. (Vector v a, KnownNat n, Ord a) => HHT v n a -> Vector v n a
+ Numeric.HHT: expectedFreq :: forall v n a. (Vector v a, KnownNat n, Fractional a) => HHT v n a -> Vector v n a
+ Numeric.HHT: hhtDenseSpectrum :: forall v n m a. (Vector v a, KnownNat n, KnownNat m, Num a) => (a -> Finite m) -> HHT v n a -> Vector n (Vector m a)
+ Numeric.HHT: hhtSparseSpectrum :: forall v n a k. (Vector v a, KnownNat n, Ord k, Num a) => (a -> k) -> HHT v n a -> Map (Finite n, k) a
- Numeric.HHT: hhtSpectrum :: forall n a k. (KnownNat n, Ord k, Num a) => (a -> k) -> HHT Vector n a -> Vector n (Map k a)
+ Numeric.HHT: hhtSpectrum :: forall v n a k. (Vector v a, KnownNat n, Ord k, Num a) => (a -> k) -> HHT v n a -> Vector n (Map k a)
Files
- CHANGELOG.md +16/−0
- emd.cabal +2/−2
- src/Numeric/EMD.hs +8/−0
- src/Numeric/EMD/Internal/Spline.hs +1/−0
- src/Numeric/HHT.hs +104/−9
CHANGELOG.md view
@@ -1,6 +1,22 @@ Changelog ========= +Version 0.1.4.0+---------------++*August 20, 2018*++<https://github.com/mstksg/emd/releases/tag/v0.1.4.0>++* `hhtSparseSpectrum` added to *Numeric.HHT* module, for an alternate sparser+ representation of the Hilbert Spectrum.+* `hhtDenseSpectrum` also added to *Numeric.HHT*, for an alternative denser+ representation.+* `expectedFrequency` added to *Numeric.HHT* module, to calculate weighted+ average of frequency contributions at each step in time.+* `dominantFrequency` also added to *Numeric.HHT* to calculate strongest+ frequency at each step in time.+ Version 0.1.3.0 ---------------
emd.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 8146e6229308d428ec6ca649537a3ddf860fe609d1d2de6ea2aff6536e75ae9e+-- hash: cae340ee4756e6a3c4e72c728779352322ea841f2e7230892d25b139b413e5f1 name: emd-version: 0.1.3.0+version: 0.1.4.0 synopsis: Empirical Mode Decomposition and Hilbert-Huang Transform description: Please see the README on GitHub at <https://github.com/mstksg/emd#readme> category: Math
src/Numeric/EMD.hs view
@@ -82,7 +82,10 @@ -- -- | Extend boundaries assuming global periodicity -- -- | BHPeriodic +-- | @since 0.1.3.0 instance Bi.Binary BoundaryHandler++-- | @since 0.1.3.0 instance Bi.Binary a => Bi.Binary (EMDOpts a) -- | Default 'EMDOpts'@@ -92,6 +95,7 @@ , eoBoundaryHandler = Just BHSymmetric } +-- | @since 0.1.3.0 instance Fractional a => Default (EMDOpts a) where def = defaultEO @@ -119,7 +123,10 @@ | SCAnd (SiftCondition a) (SiftCondition a) deriving (Show, Eq, Ord, Generic) +-- | @since 0.1.3.0 instance Bi.Binary a => Bi.Binary (SiftCondition a)++-- | @since 0.1.3.0 instance Fractional a => Default (SiftCondition a) where def = defaultSC @@ -156,6 +163,7 @@ } deriving (Show, Generic, Eq, Ord) +-- | @since 0.1.3.0 instance (VG.Vector v a, KnownNat n, Bi.Binary (v a)) => Bi.Binary (EMD v n a) where put EMD{..} = Bi.put (SVG.fromSized <$> emdIMFs) *> Bi.put (SVG.fromSized emdResidual)
src/Numeric/EMD/Internal/Spline.hs view
@@ -56,6 +56,7 @@ | SEClamped a a deriving (Show, Eq, Ord, Generic) +-- | @since 0.1.3.0 instance Bi.Binary a => Bi.Binary (SplineEnd a) data SplineCoef a = SC { _scAlpha :: !a -- ^ a
src/Numeric/HHT.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}@@ -26,11 +27,16 @@ -- @since 0.1.2.0 module Numeric.HHT (- hhtEmd+ -- * Hilbert-Huang Transform+ HHT(..), HHTLine(..)+ , hhtEmd , hht- , hhtSpectrum+ -- ** Hilbert-Huang Spectrum+ , hhtSpectrum, hhtSparseSpectrum, hhtDenseSpectrum+ -- ** Properties of spectrum , marginal, instantaneousEnergy, degreeOfStationarity- , HHT(..), HHTLine(..)+ , expectedFreq, dominantFreq+ -- ** Options , EMDOpts(..), defaultEO, BoundaryHandler(..), SiftCondition(..), defaultSC, SplineEnd(..) -- * Hilbert transforms (internal usage) , hilbert@@ -41,15 +47,16 @@ import Data.Complex import Data.Finite import Data.Fixed-import Data.List+import Data.Foldable+import Data.Maybe import Data.Proxy import Data.Semigroup import GHC.Generics (Generic) import GHC.TypeNats import Numeric.EMD import qualified Data.Binary as Bi+import qualified Data.List.NonEmpty as NE import qualified Data.Map as M-import qualified Data.Vector as V import qualified Data.Vector.Generic as VG import qualified Data.Vector.Generic.Sized as SVG import qualified Data.Vector.Sized as SV@@ -63,6 +70,7 @@ } deriving (Show, Eq, Ord, Generic) +-- | @since 0.1.3.0 instance (VG.Vector v a, KnownNat n, Bi.Binary (v a)) => Bi.Binary (HHTLine v n a) where put HHTLine{..} = Bi.put (SVG.fromSized hlMags ) *> Bi.put (SVG.fromSized hlFreqs)@@ -79,6 +87,7 @@ newtype HHT v n a = HHT { hhtLines :: [HHTLine v n a] } deriving (Show, Eq, Ord, Generic) +-- | @since 0.1.3.0 instance (VG.Vector v a, KnownNat n, Bi.Binary (v a)) => Bi.Binary (HHT v n a) -- | Directly compute the Hilbert-Huang transform of a given time series.@@ -108,18 +117,62 @@ -- -- Takes a "binning" function to allow you to specify how specific you want -- your frequencies to be.+--+-- See 'hhtSparseSpetrum' for a sparser version, and 'hhtDenseSpectrum' for+-- a denser version. hhtSpectrum- :: forall n a k. (KnownNat n, Ord k, Num a)+ :: forall v n a k. (VG.Vector v a, KnownNat n, Ord k, Num a) => (a -> k) -- ^ binning function. takes rev/tick freq between 0 and 1.- -> HHT V.Vector n a+ -> HHT v n a -> SV.Vector n (M.Map k a) hhtSpectrum f = foldl' ((SV.zipWith . M.unionWith) (+)) (pure mempty) . map go . hhtLines where- go :: HHTLine V.Vector n a -> SV.Vector n (M.Map k a)+ go :: HHTLine v n a -> SV.Vector n (M.Map k a) go HHTLine{..} = SV.generate $ \i -> M.singleton (f $ hlFreqs `SVG.index` i) (hlMags `SVG.index` i) --- | Compute the marginal spectrum given a Hilbert-Huang Transform.+-- | A sparser vesion of 'hhtSpectrum'. Compute the full Hilbert-Huang+-- Transform spectrum. Returns a /sparse/ matrix representing the power at+-- each time step (the @'Finite' n@) and frequency (the @k@).+--+-- Takes a "binning" function to allow you to specify how specific you want+-- your frequencies to be.+--+-- @since 0.1.4.0+hhtSparseSpectrum+ :: forall v n a k. (VG.Vector v a, KnownNat n, Ord k, Num a)+ => (a -> k) -- ^ binning function. takes rev/tick freq between 0 and 1.+ -> HHT v n a+ -> M.Map (Finite n, k) a+hhtSparseSpectrum f = M.unionsWith (+) . concatMap go . hhtLines+ where+ go :: HHTLine v n a -> [M.Map (Finite n, k) a]+ go HHTLine{..} = flip fmap (finites @n) $ \i ->+ M.singleton (i, f $ hlFreqs `SVG.index` i) $+ hlMags `SVG.index` i++-- | A denser version of 'hhtSpectrum'. Compute the full Hilbert-Huang+-- Transform spectrum, returning a dense matrix (as a vector of vectors)+-- representing the power at each time step and each frequency.+--+-- Takes a "binning" function that maps a frequency to one of @m@ discrete+-- slots, for accumulation in the dense matrix.+--+-- @since 0.1.4.0+hhtDenseSpectrum+ :: forall v n m a. (VG.Vector v a, KnownNat n, KnownNat m, Num a)+ => (a -> Finite m) -- ^ binning function. takes rev/tick freq between 0 and 1.+ -> HHT v n a+ -> SV.Vector n (SV.Vector m a)+hhtDenseSpectrum f h = SV.generate $ \i -> SV.generate $ \j ->+ M.findWithDefault 0 (i, j) ss+ where+ ss = hhtSparseSpectrum f h++-- | Compute the marginal spectrum given a Hilbert-Huang Transform. It is+-- similar to a Fourier Transform; it provides the "total power" over the+-- entire time series for each frequency component.+-- -- A binning function is accepted to allow you to specify how specific you -- want your frequencies to be. marginal@@ -132,6 +185,48 @@ go :: HHTLine v n a -> [M.Map k a] go HHTLine{..} = flip fmap (finites @n) $ \i -> M.singleton (f $ hlFreqs `SVG.index` i) (hlMags `SVG.index` i)++-- | Returns the "expected value" of frequency at each time step,+-- calculated as a weighted average of all contributions at every frequency+-- at that time step.+--+-- @since 0.1.4.0+expectedFreq+ :: forall v n a. (VG.Vector v a, KnownNat n, Fractional a)+ => HHT v n a+ -> SVG.Vector v n a+expectedFreq HHT{..} = SVG.generate $ \i -> weightedAverage . map (go i) $ hhtLines+ where+ go :: Finite n -> HHTLine v n a -> (a, a)+ go i HHTLine{..} = (hlFreqs `SVG.index` i, hlMags `SVG.index` i)++weightedAverage+ :: (Foldable t, Fractional a)+ => t (a, a)+ -> a+weightedAverage = uncurry (/) . foldl' go (0, 0)+ where+ go (!sx, !sw) (!x, !w) = (sx + x, sw + w)++-- | Returns the dominant frequency (frequency with largest magnitude+-- contribution) at each time step.+-- +-- @since 0.1.4.0+dominantFreq+ :: forall v n a. (VG.Vector v a, KnownNat n, Ord a)+ => HHT v n a+ -> SVG.Vector v n a+dominantFreq HHT{..} = SVG.generate $ \i -> (\(Max (Arg _ x)) -> x)+ . sconcat+ . fromMaybe err+ . NE.nonEmpty+ . map (go i)+ $ hhtLines+ where+ go :: Finite n -> HHTLine v n a -> ArgMax a a+ go i HHTLine{..} = Max $ Arg (hlMags `SVG.index` i)+ (hlFreqs `SVG.index` i)+ err = errorWithoutStackTrace "Numeric.HHT.dominantFreq: HHT was formed with no Intrinsic Mode Functions" -- | Compute the instantaneous energy of the time series at every step via -- the Hilbert-Huang Transform.