packages feed

emd 0.1.10.0 → 0.2.0.0

raw patch · 9 files changed

+495/−413 lines, 9 filesdep +conduinoPVP ok

version bump matches the API change (PVP)

Dependencies added: conduino

API changes (from Hackage documentation)

- Numeric.EMD: SCAnd :: SiftCondition a -> SiftCondition a -> SiftCondition a
- Numeric.EMD: SCCauchy :: SiftProjection -> !a -> SiftCondition a
- Numeric.EMD: SCOr :: SiftCondition a -> SiftCondition a -> SiftCondition a
- Numeric.EMD: SCProj :: SiftProjection -> !a -> SiftCondition a
- Numeric.EMD: SCSCond :: !Int -> SiftCondition a
- Numeric.EMD: SCStdDev :: !a -> SiftCondition a
- Numeric.EMD: SCTimes :: !Int -> SiftCondition a
- Numeric.EMD: SPEnergyDiff :: SiftProjection
- Numeric.EMD: SPEnvMeanSum :: SiftProjection
- Numeric.EMD: [eoSiftCondition] :: EMDOpts a -> SiftCondition a
- Numeric.EMD: data SiftCondition a
- Numeric.EMD: data SiftProjection
- Numeric.EMD: defaultSC :: Fractional a => SiftCondition a
- Numeric.EMD: scEnergyDiff :: a -> a -> SiftCondition a
- Numeric.HHT: SCAnd :: SiftCondition a -> SiftCondition a -> SiftCondition a
- Numeric.HHT: SCCauchy :: SiftProjection -> !a -> SiftCondition a
- Numeric.HHT: SCOr :: SiftCondition a -> SiftCondition a -> SiftCondition a
- Numeric.HHT: SCProj :: SiftProjection -> !a -> SiftCondition a
- Numeric.HHT: SCSCond :: !Int -> SiftCondition a
- Numeric.HHT: SCStdDev :: !a -> SiftCondition a
- Numeric.HHT: SCTimes :: !Int -> SiftCondition a
- Numeric.HHT: [eoSiftCondition] :: EMDOpts a -> SiftCondition a
- Numeric.HHT: data SiftCondition a
- Numeric.HHT: defaultSC :: Fractional a => SiftCondition a
+ Numeric.EMD: [eoSifter] :: EMDOpts v n a -> Sifter v n a
+ Numeric.EMD: data Sifter v n a
+ Numeric.EMD: defaultSifter :: (Vector v a, Fractional a, Ord a) => Sifter v n a
+ Numeric.EMD: instance (Data.Vector.Generic.Base.Vector v a, GHC.Real.Fractional a, GHC.Classes.Ord a) => Data.Default.Class.Default (Numeric.EMD.Internal.EMDOpts v n a)
+ Numeric.EMD.Sift: SRIMF :: !Vector v n a -> !Int -> SiftResult v n a
+ Numeric.EMD.Sift: SRResidual :: !Vector v n a -> SiftResult v n a
+ Numeric.EMD.Sift: Sifter :: Pipe (SingleSift v n a) Void Void (SM v n a) () -> Sifter v n a
+ Numeric.EMD.Sift: SingleSift :: !Vector v n a -> !Vector v n a -> !Vector v n a -> SingleSift v n a
+ Numeric.EMD.Sift: [sPipe] :: Sifter v n a -> Pipe (SingleSift v n a) Void Void (SM v n a) ()
+ Numeric.EMD.Sift: [ssMaxEnv] :: SingleSift v n a -> !Vector v n a
+ Numeric.EMD.Sift: [ssMinEnv] :: SingleSift v n a -> !Vector v n a
+ Numeric.EMD.Sift: [ssResult] :: SingleSift v n a -> !Vector v n a
+ Numeric.EMD.Sift: data SiftResult v n a
+ Numeric.EMD.Sift: data SingleSift v n a
+ Numeric.EMD.Sift: defaultSifter :: (Vector v a, Fractional a, Ord a) => Sifter v n a
+ Numeric.EMD.Sift: energyDiff :: (Vector v a, Floating a) => SingleSift v n a -> SM v n a a
+ Numeric.EMD.Sift: envMean :: (Vector v a, KnownNat n, Floating a) => SingleSift v n a -> SM v n a a
+ Numeric.EMD.Sift: envelopes :: (Vector v a, KnownNat n, Fractional a, Ord a) => SplineEnd a -> Maybe BoundaryHandler -> Vector v (n + 1) a -> Maybe (Vector v (n + 1) a, Vector v (n + 1) a)
+ Numeric.EMD.Sift: infixr 2 `siftOr`
+ Numeric.EMD.Sift: infixr 3 `siftAnd`
+ Numeric.EMD.Sift: instance (Data.Vector.Generic.Base.Vector v a, GHC.Real.Fractional a, GHC.Classes.Ord a) => Data.Default.Class.Default (Numeric.EMD.Internal.Sifter v n a)
+ Numeric.EMD.Sift: newtype Sifter v n a
+ Numeric.EMD.Sift: normalizeProj :: (Vector v a, KnownNat n, Floating a) => (SingleSift v n a -> SM v n a a) -> SingleSift v n a -> SM v n a a
+ Numeric.EMD.Sift: rms :: (Vector v a, KnownNat n, Floating a) => Vector v n a -> a
+ Numeric.EMD.Sift: sift :: forall v n a. (Vector v a, KnownNat n, Floating a, Ord a) => EMDOpts v (n + 1) a -> Vector v (n + 1) a -> SiftResult v (n + 1) a
+ Numeric.EMD.Sift: siftAnd :: Sifter v n a -> Sifter v n a -> Sifter v n a
+ Numeric.EMD.Sift: siftCauchy :: (Fractional b, Ord b) => (SingleSift v n a -> b) -> b -> Sifter v n a
+ Numeric.EMD.Sift: siftEnergyDiff :: (Vector v a, KnownNat n, Floating a, Ord a) => a -> a -> Sifter v n a
+ Numeric.EMD.Sift: siftOr :: Sifter v n a -> Sifter v n a -> Sifter v n a
+ Numeric.EMD.Sift: siftPairs :: Ord b => (SingleSift v n a -> SingleSift v n a -> SM v n a b) -> b -> Sifter v n a
+ Numeric.EMD.Sift: siftPairs_ :: (SingleSift v n a -> SingleSift v n a -> SM v n a Bool) -> Sifter v n a
+ Numeric.EMD.Sift: siftProj :: Ord b => (SingleSift v n a -> SM v n a b) -> b -> Sifter v n a
+ Numeric.EMD.Sift: siftProj_ :: (SingleSift v n a -> SM v n a Bool) -> Sifter v n a
+ Numeric.EMD.Sift: siftSCond :: (Vector v a, KnownNat n, Fractional a, Ord a) => Int -> Sifter v (n + 1) a
+ Numeric.EMD.Sift: siftStdDev :: forall v n a. (Vector v a, Fractional a, Ord a) => a -> Sifter v n a
+ Numeric.EMD.Sift: siftTimes :: Int -> Sifter v n a
+ Numeric.EMD.Sift: type SM v n a = Reader (Vector v n a)
+ Numeric.HHT: [eoSifter] :: EMDOpts v n a -> Sifter v n a
+ Numeric.HHT: defaultSifter :: (Vector v a, Fractional a, Ord a) => Sifter v n a
- Numeric.EMD: EO :: SiftCondition a -> SplineEnd a -> Maybe BoundaryHandler -> EMDOpts a
+ Numeric.EMD: EO :: Sifter v n a -> SplineEnd a -> Maybe BoundaryHandler -> EMDOpts v n a
- Numeric.EMD: [eoBoundaryHandler] :: EMDOpts a -> Maybe BoundaryHandler
+ Numeric.EMD: [eoBoundaryHandler] :: EMDOpts v n a -> Maybe BoundaryHandler
- Numeric.EMD: [eoSplineEnd] :: EMDOpts a -> SplineEnd a
+ Numeric.EMD: [eoSplineEnd] :: EMDOpts v n a -> SplineEnd a
- Numeric.EMD: data EMDOpts a
+ Numeric.EMD: data EMDOpts v n a
- Numeric.EMD: defaultEO :: Fractional a => EMDOpts a
+ Numeric.EMD: defaultEO :: (Vector v a, Fractional a, Ord a) => EMDOpts v n a
- Numeric.EMD: emd :: (Vector v a, KnownNat n, Floating a, Ord a) => EMDOpts a -> Vector v (n + 1) a -> EMD v (n + 1) a
+ Numeric.EMD: emd :: (Vector v a, KnownNat n, Floating a, Ord a) => EMDOpts v (n + 1) a -> Vector v (n + 1) a -> EMD v (n + 1) a
- Numeric.EMD: emd' :: (Vector v a, KnownNat n, Floating a, Ord a, Applicative m) => (SiftResult v (n + 1) a -> m r) -> EMDOpts a -> Vector v (n + 1) a -> m (EMD v (n + 1) a)
+ Numeric.EMD: emd' :: (Vector v a, KnownNat n, Floating a, Ord a, Applicative m) => (SiftResult v (n + 1) a -> m r) -> EMDOpts v (n + 1) a -> Vector v (n + 1) a -> m (EMD v (n + 1) a)
- Numeric.EMD: emdTrace :: (Vector v a, KnownNat n, Floating a, Ord a, MonadIO m) => EMDOpts a -> Vector v (n + 1) a -> m (EMD v (n + 1) a)
+ Numeric.EMD: emdTrace :: (Vector v a, KnownNat n, Floating a, Ord a, MonadIO m) => EMDOpts v (n + 1) a -> Vector v (n + 1) a -> m (EMD v (n + 1) a)
- Numeric.EMD: sift :: forall v n a. (Vector v a, KnownNat n, Floating a, Ord a) => EMDOpts a -> Vector v (n + 1) a -> SiftResult v (n + 1) a
+ Numeric.EMD: sift :: forall v n a. (Vector v a, KnownNat n, Floating a, Ord a) => EMDOpts v (n + 1) a -> Vector v (n + 1) a -> SiftResult v (n + 1) a
- Numeric.HHT: EO :: SiftCondition a -> SplineEnd a -> Maybe BoundaryHandler -> EMDOpts a
+ Numeric.HHT: EO :: Sifter v n a -> SplineEnd a -> Maybe BoundaryHandler -> EMDOpts v n a
- Numeric.HHT: [eoBoundaryHandler] :: EMDOpts a -> Maybe BoundaryHandler
+ Numeric.HHT: [eoBoundaryHandler] :: EMDOpts v n a -> Maybe BoundaryHandler
- Numeric.HHT: [eoSplineEnd] :: EMDOpts a -> SplineEnd a
+ Numeric.HHT: [eoSplineEnd] :: EMDOpts v n a -> SplineEnd a
- Numeric.HHT: data EMDOpts a
+ Numeric.HHT: data EMDOpts v n a
- Numeric.HHT: defaultEO :: Fractional a => EMDOpts a
+ Numeric.HHT: defaultEO :: (Vector v a, Fractional a, Ord a) => EMDOpts v n a
- Numeric.HHT: hht :: forall v n a. (Vector v a, Vector v (Complex a), KnownNat n, FFTWReal a) => EMDOpts a -> Vector v (n + 1) a -> HHT v n a
+ Numeric.HHT: hht :: forall v n a. (Vector v a, Vector v (Complex a), KnownNat n, FFTWReal a) => EMDOpts v (n + 1) a -> Vector v (n + 1) a -> HHT v n a

Files

CHANGELOG.md view
@@ -1,6 +1,16 @@ Changelog ========= +Version 0.2.0.0+---------------++*October 30, 2019*++<https://github.com/mstksg/emd/releases/tag/v0.2.0.0>++*   Sift condition system totally revamped, allowing for custom sift+    conditions.+ Version 0.1.10.0 --------------- 
emd.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 5230a7607e7d3f26121daa88b982f8f58087a236adc506e45eadf1a038581d7a+-- hash: 3facd98354d5dd814f0bea76e951d633090222a995f013f939679dc36a60f586  name:           emd-version:        0.1.10.0+version:        0.2.0.0 synopsis:       Empirical Mode Decomposition and Hilbert-Huang Transform description:    Empirical Mode decomposition and Hilbert-Huang Transform in pure                 Haskell.@@ -34,11 +34,12 @@   exposed-modules:       Numeric.EMD       Numeric.EMD.Internal.Spline+      Numeric.EMD.Sift       Numeric.HHT   other-modules:+      Numeric.EMD.Internal       Numeric.EMD.Internal.Extrema       Numeric.EMD.Internal.Pipe-      Numeric.EMD.Internal.Sift       Numeric.EMD.Internal.Tridiagonal       Numeric.HHT.Internal.FFT   hs-source-dirs:@@ -49,6 +50,7 @@     , base >=4.11 && <5     , binary     , carray+    , conduino     , containers     , data-default-class     , deepseq@@ -88,6 +90,7 @@     , tasty-hedgehog     , tasty-hunit     , typelits-witnesses+    , vector     , vector-sized   default-language: Haskell2010 
src/Numeric/EMD.hs view
@@ -8,12 +8,13 @@ {-# LANGUAGE TypeApplications                         #-} {-# LANGUAGE TypeInType                               #-} {-# LANGUAGE TypeOperators                            #-}+{-# OPTIONS_GHC -Wno-orphans                          #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-} {-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise       #-}  -- | -- Module      : Numeric.EMD--- Copyright   : (c) Justin Le 2018+-- Copyright   : (c) Justin Le 2019 -- License     : BSD3 -- -- Maintainer  : justin@jle.im@@ -38,7 +39,6 @@ -- 'Data.Vector.Sized.toSized' (for when you know the size at compile-time) -- and 'Data.Vector.Sized.withSized' (for when you don't). --- module Numeric.EMD (   -- * Empirical Mode Decomposition     emd@@ -49,8 +49,8 @@   -- ** Configuration   , EMDOpts(..), defaultEO   , BoundaryHandler(..)-  , SiftCondition(..), SiftProjection(..), defaultSC-  , scEnergyDiff+  , Sifter+  , defaultSifter   , SplineEnd(..)   -- * Internal   , sift, SiftResult(..)@@ -59,16 +59,40 @@  import           Control.DeepSeq import           Control.Monad.IO.Class+import           Data.Default.Class import           Data.Functor.Identity import           Data.List-import           GHC.Generics              (Generic)+import           GHC.Generics                (Generic) import           GHC.TypeNats-import           Numeric.EMD.Internal.Sift+import           Numeric.EMD.Internal+import           Numeric.EMD.Internal.Spline+import           Numeric.EMD.Sift import           Text.Printf-import qualified Data.Binary               as Bi-import qualified Data.Vector.Generic       as VG-import qualified Data.Vector.Generic.Sized as SVG+import qualified Data.Binary                 as Bi+import qualified Data.Vector.Generic         as VG+import qualified Data.Vector.Generic.Sized   as SVG +-- | Default 'EMDOpts'+--+-- Note: If you immediately use this and set 'eoSifter', then @v@ will be+-- ambiguous.  Explicitly set @v@ with type applications to appease GHC+--+-- @+-- 'defaultEO' @(Data.Vector.Vector)+--    { eoSifter = scTimes 100+--    }+-- @+defaultEO :: (VG.Vector v a, Fractional a, Ord a) => EMDOpts v n a+defaultEO = EO { eoSifter          = defaultSifter+               , eoSplineEnd       = SENatural+               , eoBoundaryHandler = Just BHSymmetric+               }++-- | @since 0.1.3.0+instance (VG.Vector v a, Fractional a, Ord a) => Default (EMDOpts v n a) where+    def = defaultEO++ -- | An @'EMD' v n a@ is an Empirical Mode Decomposition of a time series -- with @n@ items of type @a@ stored in a vector @v@. --@@ -100,7 +124,7 @@ --     the input vector -- 2.  We provide a vector of size of at least one. emd :: (VG.Vector v a, KnownNat n, Floating a, Ord a)-    => EMDOpts a+    => EMDOpts v (n + 1) a     -> SVG.Vector v (n + 1) a     -> EMD v (n + 1) a emd eo = runIdentity . emd' (const (pure ())) eo@@ -109,7 +133,7 @@ -- debugging to see how long each step is taking. emdTrace     :: (VG.Vector v a, KnownNat n, Floating a, Ord a, MonadIO m)-    => EMDOpts a+    => EMDOpts v (n + 1) a     -> SVG.Vector v (n + 1) a     -> m (EMD v (n + 1) a) emdTrace = emd' $ \case@@ -120,7 +144,7 @@ emd'     :: (VG.Vector v a, KnownNat n, Floating a, Ord a, Applicative m)     => (SiftResult v (n + 1) a -> m r)-    -> EMDOpts a+    -> EMDOpts v (n + 1) a     -> SVG.Vector v (n + 1) a     -> m (EMD v (n + 1) a) emd' cb eo = go id
+ src/Numeric/EMD/Internal.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE DeriveGeneric #-}++module Numeric.EMD.Internal (+    EMDOpts(..)+  , BoundaryHandler(..)+  , Sifter(..)+  , SM+  , SingleSift(..)+  ) where++import           Control.Monad.Trans.Reader+import           Data.Conduino+import           Data.Void+import           GHC.Generics+import           Numeric.EMD.Internal.Spline+import qualified Data.Binary                 as Bi+import qualified Data.Vector.Generic.Sized   as SVG++-- | Options for EMD composition.+data EMDOpts v n a = EO+    { eoSifter          :: Sifter v n a           -- ^ stop condition for sifting+    , eoSplineEnd       :: SplineEnd a            -- ^ end conditions for envelope splines+    , eoBoundaryHandler :: Maybe BoundaryHandler  -- ^ process for handling boundary+    }+  deriving (Generic)++-- | Boundary conditions for splines.+data BoundaryHandler+    -- | Clamp envelope at end points (Matlab implementation)+    = BHClamp+    -- | Extend boundaries symmetrically+    | BHSymmetric+  deriving (Show, Eq, Ord, Generic)++-- | @since 0.1.3.0+instance Bi.Binary BoundaryHandler++-- | Result of a single sift+data SingleSift v n a = SingleSift+    { ssResult :: !(SVG.Vector v n a)+    , ssMinEnv :: !(SVG.Vector v n a)+    , ssMaxEnv :: !(SVG.Vector v n a)+    }++-- | Monad where 'Sifter' actions live.  The reader parameter is the+-- "original vector".+type SM v n a = Reader (SVG.Vector v n a)++-- | A sift stopping condition.+--+-- It is a 'Pipe' consumer that takes single sift step results upstream and+-- terminates with '()' as soon as it is satisfied with the latest sift+-- step.+--+-- Use combinators like 'siftOr' and 'siftAnd' to combine sifters, and the+-- various sifters in "Numeric.EMD.Sift" to create sifters from commonly+-- established ones or new ones from scratch.+--+-- @since 0.2.0.0+newtype Sifter v n a = Sifter { sPipe :: Pipe (SingleSift v n a) Void Void (SM v n a) () }+
− src/Numeric/EMD/Internal/Sift.hs
@@ -1,384 +0,0 @@-{-# LANGUAGE BangPatterns                             #-}-{-# LANGUAGE DeriveGeneric                            #-}-{-# LANGUAGE GADTs                                    #-}-{-# LANGUAGE LambdaCase                               #-}-{-# LANGUAGE RankNTypes                               #-}-{-# LANGUAGE RecordWildCards                          #-}-{-# LANGUAGE ScopedTypeVariables                      #-}-{-# LANGUAGE TypeApplications                         #-}-{-# LANGUAGE TypeInType                               #-}-{-# LANGUAGE TypeOperators                            #-}-{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}-{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise       #-}---module Numeric.EMD.Internal.Sift (-    EMDOpts(..), defaultEO-  , BoundaryHandler(..)-  , SiftCondition(..), SiftProjection(..), defaultSC-  , scEnergyDiff-  , SplineEnd(..)-  -- * Internal-  , sift, SiftResult(..)-  , envelopes-  ) where--import           Control.Applicative-import           Control.Monad-import           Control.Monad.Trans.State-import           Data.Default.Class-import           Data.Finite-import           Data.Void-import           GHC.Generics                 (Generic)-import           GHC.TypeNats-import           Numeric.EMD.Internal.Extrema-import           Numeric.EMD.Internal.Pipe-import           Numeric.EMD.Internal.Spline-import qualified Data.Binary                  as Bi-import qualified Data.Map                     as M-import qualified Data.Vector.Generic          as VG-import qualified Data.Vector.Generic.Sized    as SVG---- | Options for EMD composition.-data EMDOpts a = EO { eoSiftCondition   :: SiftCondition a  -- ^ stop condition for sifting-                    , eoSplineEnd       :: SplineEnd a      -- ^ end conditions for envelope splines-                    , eoBoundaryHandler :: Maybe BoundaryHandler  -- ^ process for handling boundary-                    }-  deriving (Show, Eq, Ord, Generic)---- | @since 0.1.3.0-instance Bi.Binary a => Bi.Binary (EMDOpts a)---- | Default 'EMDOpts'-defaultEO :: Fractional a => EMDOpts a-defaultEO = EO { eoSiftCondition   = defaultSC-               , eoSplineEnd       = SENatural-               , eoBoundaryHandler = Just BHSymmetric-               }---- | @since 0.1.3.0-instance Fractional a => Default (EMDOpts a) where-    def = defaultEO----- | Boundary conditions for splines.-data BoundaryHandler-    -- | Clamp envelope at end points (Matlab implementation)-    = BHClamp-    -- | Extend boundaries symmetrically-    | BHSymmetric-  deriving (Show, Eq, Ord, Generic)---- | @since 0.1.3.0-instance Bi.Binary BoundaryHandler---- | Stop conditions for sifting process------ Data type is lazy in its fields, so this infinite data type:------ @--- nTimes n = SCTimes n `SCOr` nTimes (n + 1)--- @------ will be treated identically as:------ @--- nTimes = SCTimes--- @-data SiftCondition a-    -- | Stop using standard SD method-    = SCStdDev !a-    -- | When the difference between successive items reaches a given threshold-    -- \(\tau\)-    ---    -- \[-    -- \frac{\left(f(t-1) - f(t)\right)^2}{f^2(t-1)} < \tau-    -- \]-    ---    -- @since 0.1.10.0-    | SCCauchy SiftProjection !a-    -- | When the value reaches a given threshold \(\tau\)-    ---    -- \[-    -- f(t) < \tau-    -- \]-    ---    -- @since 0.1.10.0-    | SCProj   SiftProjection !a-    -- | S-condition criteria.-    ---    -- The S-number is the length of current streak where number of extrema-    -- or zero crossings all differ at most by one.-    ---    -- Stop sifting when the S-number reaches a given amount.-    ---    -- @since 0.1.10.0-    | SCSCond !Int-    -- | Stop after a fixed number of sifting iterations-    | SCTimes !Int-    -- | One or the other-    | SCOr (SiftCondition a) (SiftCondition a)-    -- | Stop when both conditions are met-    | SCAnd (SiftCondition a) (SiftCondition a)-  deriving (Show, Eq, Ord, Generic)---- | A projection of sifting data.  Used as a part of 'SiftCondition' to--- describe 'SCCauchy' and 'SCProj'.------ @since 0.1.10.0-data SiftProjection-    -- | The root mean square of the envelope means-    = SPEnvMeanSum-    -- | The "energy difference" quotient (Cheng, Yu, Yang 2005)-    | SPEnergyDiff-  deriving (Show, Eq, Ord, Generic)--instance Bi.Binary SiftProjection---- | @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---- | Default 'SiftCondition'-defaultSC :: Fractional a => SiftCondition a-defaultSC = SCStdDev 0.3 `SCOr` SCTimes 50     -- R package uses SCTimes 20, Matlab uses no limit----- | Cheng, Yu, Yang suggest pairing together an energy difference--- threshold with a threshold for mean envelope RMS.  This is a convenience--- function to construct that pairing.-scEnergyDiff-    :: a                -- ^ Threshold for Energy Difference-    -> a                -- ^ Threshold for mean envelope RMS-    -> SiftCondition a-scEnergyDiff s t = SCProj SPEnergyDiff s `SCAnd` SCProj SPEnvMeanSum t----- | The result of a sifting operation.  Each sift either yields--- a residual, or a new IMF.-data SiftResult v n a = SRResidual !(SVG.Vector v n a)-                      | SRIMF      !(SVG.Vector v n a) !Int   -- ^ number of sifting iterations---- | Result of a single sift-data SingleSift v n a = SingleSift-    { ssRes    :: !(SVG.Vector v n a)-    , ssMinEnv :: !(SVG.Vector v n a)-    , ssMaxEnv :: !(SVG.Vector v n a)-    }--type Sifter v n m a = Pipe (SingleSift v n a) Void Void m ()--siftTimes :: Int -> Sifter v n m a-siftTimes n = dropP (n - 1) >> void awaitSurely--siftProj :: (SingleSift v n a -> Bool) -> Sifter v n m a-siftProj p = go-  where-    go = do-      v <- awaitSurely-      unless (p v) go--siftPairs :: (SingleSift v n a -> SingleSift v n a -> Bool) -> Sifter v n m a-siftPairs p = go =<< awaitSurely-  where-    go s = do-      s' <- awaitSurely-      unless (p s s') (go s')--siftStdDev :: forall v n m a. (VG.Vector v a, Fractional a, Ord a) => a -> Sifter v n m a-siftStdDev t = siftPairs $ \(SingleSift v _ _) (SingleSift v' _ _) ->-    SVG.sum (SVG.zipWith (\x x' -> (x-x')^(2::Int) / (x^(2::Int) + eps)) v v')-      <= t-  where-    eps = 0.0000001--siftCauchy-    :: (Fractional b, Ord b)-    => (SingleSift v n a -> b)-    -> b-    -> Sifter v n m a-siftCauchy p t = siftPairs $ \s s' ->-  let ps  = p s-      ps' = p s'-      δ   = ps' - ps-  in  ((δ * δ) / (ps * ps)) <= t--siftSCond :: (VG.Vector v a, KnownNat n, Fractional a, Ord a) => Int -> Sifter v (n + 1) m a-siftSCond n = go []-  where-    go cxs = do-      v <- awaitSurely-      let cx   = crossCount $ ssRes v-          done = all ((<= 1) . abs . subtract cx) cxs-      unless done $-        go (take (n - 1) (cx : cxs))-    crossCount xs = M.size mins + M.size maxs + crosses-      where-        (mins, maxs) = extrema xs-        crosses = fst . flip execState (0, Nothing) . flip SVG.mapM_ xs $ \x -> modify $ \(!i, !y) ->-          let xPos = x > 0-              i'   = case y of-                       Nothing -> i-                       Just y'-                         | xPos == y' -> i-                         | otherwise  -> i + 1-          in  (i', Just xPos)--siftOr :: Monad m => Sifter v n m a -> Sifter v n m a -> Sifter v n m a-siftOr p q = getZipSink $ ZipSink p <|> ZipSink q--siftAnd :: Monad m => Sifter v n m a -> Sifter v n m a -> Sifter v n m a-siftAnd p q = getZipSink $ ZipSink p *> ZipSink q--toSifter-    :: (VG.Vector v a, KnownNat n, Monad m, Floating a, Ord a)-    => SVG.Vector v (n + 1) a-    -> SiftCondition a-    -> Sifter v (n + 1) m a-toSifter v0 = go-  where-    go = \case-      SCStdDev x -> siftStdDev x-      SCCauchy p x -> siftCauchy (toProj p v0) x-      SCProj   p x -> siftProj ((<= x) . toProj p v0)-      SCSCond  n   -> siftSCond n-      SCTimes  i -> siftTimes i-      SCOr p q   -> siftOr (go p) (go q)-      SCAnd p q  -> siftAnd (go p) (go q)--toProj-    :: (VG.Vector v a, Floating a)-    => SiftProjection-    -> SVG.Vector v n a-    -> SingleSift v n a-    -> a-toProj = \case-    SPEnvMeanSum -> \_ SingleSift{..} ->-      sqrt . squareMag $ SVG.zipWith (\x y -> (x + y) / 2) ssMinEnv ssMaxEnv-    SPEnergyDiff -> \v0 ->-      let eX = squareMag v0-      in  \SingleSift{..} ->-            let eTot = squareMag ssRes - squareMag (SVG.zipWith (-) v0 ssRes)-            in  abs $ eX - eTot-  where-    squareMag = SVG.foldl' (\s x -> s + x*x) 0----- | Iterated sifting process, used to produce either an IMF or a residual.-sift-    :: forall v n a. (VG.Vector v a, KnownNat n, Floating a, Ord a)-    => EMDOpts a-    -> SVG.Vector v (n + 1) a-    -> SiftResult v (n + 1) a-sift EO{..} v0 = case execStateT (runPipe sifterPipe) (0, v0) of-    Left  v        -> SRResidual v-    Right (!i, !v) -> SRIMF v i-  where-    sifterPipe = repeatM go-              .| toSifter v0 eoSiftCondition-    go = StateT $ \(!i, !v) ->-      case sift' eoSplineEnd eoBoundaryHandler v of-        Nothing                -> Left v-        Just ss@SingleSift{..} -> Right (ss, (i + 1, ssRes))---- | Single sift-sift'-    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)-    => SplineEnd a-    -> Maybe BoundaryHandler-    -> SVG.Vector v (n + 1) a-    -> Maybe (SingleSift v (n + 1) a)-sift' se bh v = do-    (mins, maxs) <- envelopes se bh v-    pure SingleSift-      { ssRes    = SVG.zipWith3 (\x mi ma -> x - (mi + ma)/2) v mins maxs-      , ssMinEnv = mins-      , ssMaxEnv = maxs-      }---- | Returns cubic splines of local minimums and maximums.  Returns--- 'Nothing' if there are not enough local minimum or maximums to create--- the splines.-envelopes-    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)-    => SplineEnd a-    -> Maybe BoundaryHandler-    -> SVG.Vector v (n + 1) a-    -> Maybe (SVG.Vector v (n + 1) a, SVG.Vector v (n + 1) a)-envelopes se bh xs = do-    when (bh == Just BHClamp) $ do-      guard (M.size mins > 1)-      guard (M.size maxs > 1)-    (,) <$> splineAgainst se emin mins-        <*> splineAgainst se emax maxs-  where-    -- minMax = M.fromList [(minBound, SVG.head xs), (maxBound, SVG.last xs)]-    (mins,maxs) = extrema xs-    (emin,emax) = case bh of-      Nothing  -> mempty-      Just bh' -> extendExtrema xs bh' (mins,maxs)-    --   | isJust bh = (mins `M.union` minMax, maxs `M.union` minMax)-    --   | otherwise = (mins, maxs)--extendExtrema-    :: forall v n a. (VG.Vector v a, KnownNat n)-    => SVG.Vector v (n + 1) a-    -> BoundaryHandler-    -> (M.Map (Finite (n + 1)) a, M.Map (Finite (n + 1)) a)-    -> (M.Map Int a, M.Map Int a)-    -- (M.Map (Finite (n + 1)) a, M.Map (Finite (n + 1)) a)-extendExtrema xs = \case-    BHClamp     -> const (firstLast, firstLast)-    BHSymmetric -> \(mins, maxs) ->-      let addFirst = case (flippedMin, flippedMax) of-              (Nothing      , Nothing      ) -> mempty-              -- first point is local maximum-              (Just (_,mn)  , Nothing      ) -> (mn        , firstPoint)-              -- first point is local minimum-              (Nothing      , Just (_,mx)  ) -> (firstPoint, mx        )-              (Just (mni,mn), Just (mxi,mx))-                | mni < mxi                  -> (mn        , firstPoint)-                | otherwise                  -> (firstPoint, mx        )-            where-              flippedMin = flip fmap (M.lookupMin mins) $ \(minIx, minVal) ->-                (minIx, M.singleton (negate (fromIntegral minIx)) minVal)-              flippedMax = flip fmap (M.lookupMin maxs) $ \(maxIx, maxVal) ->-                (maxIx, M.singleton (negate (fromIntegral maxIx)) maxVal)-          addLast = case (flippedMin, flippedMax) of-              (Nothing      , Nothing      ) -> mempty-              -- last point is local maximum-              (Just (_,mn)  , Nothing      ) -> (mn        , lastPoint )-              -- last point is local minimum-              (Nothing      , Just (_,mx)  ) -> (lastPoint , mx        )-              (Just (mni,mn), Just (mxi,mx))-                | mni > mxi                  -> (mn        , lastPoint )-                | otherwise                  -> (lastPoint , mx        )-            where-              flippedMin = flip fmap (M.lookupMax mins) $ \(minIx, minVal) ->-                (minIx, M.singleton (extendSym (fromIntegral minIx)) minVal)-              flippedMax = flip fmap (M.lookupMax maxs) $ \(maxIx, maxVal) ->-                (maxIx, M.singleton (extendSym (fromIntegral maxIx)) maxVal)-      in  addFirst `mappend` addLast-  where-    lastIx = fromIntegral $ maxBound @(Finite n)-    firstPoint = M.singleton 0 (SVG.head xs)-    lastPoint  = M.singleton lastIx (SVG.last xs)-    firstLast  = firstPoint `mappend` lastPoint-    extendSym i = 2 * lastIx - i---- | Build a splined vector against a map of control points.-splineAgainst-    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)-    => SplineEnd a-    -> M.Map Int a              -- ^ extensions-    -> M.Map (Finite n) a-    -> Maybe (SVG.Vector v n a)-splineAgainst se ext = fmap go-                     . makeSpline se-                     . mappend (M.mapKeysMonotonic fromIntegral ext)-                     . M.mapKeysMonotonic fromIntegral-  where-    go spline = SVG.generate (sampleSpline spline . fromIntegral)
src/Numeric/EMD/Internal/Spline.hs view
@@ -12,7 +12,7 @@  -- | -- Module      : Numeric.EMD.Internal.Spline--- Copyright   : (c) Justin Le 2018+-- Copyright   : (c) Justin Le 2019 -- License     : BSD3 -- -- Maintainer  : justin@jle.im
+ src/Numeric/EMD/Sift.hs view
@@ -0,0 +1,365 @@+{-# LANGUAGE BangPatterns                             #-}+{-# LANGUAGE GADTs                                    #-}+{-# LANGUAGE LambdaCase                               #-}+{-# LANGUAGE RankNTypes                               #-}+{-# LANGUAGE RecordWildCards                          #-}+{-# LANGUAGE ScopedTypeVariables                      #-}+{-# LANGUAGE TypeApplications                         #-}+{-# LANGUAGE TypeInType                               #-}+{-# LANGUAGE TypeOperators                            #-}+{-# OPTIONS_GHC -Wno-orphans                          #-}+{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}+{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise       #-}++-- |+-- Module      : Numeric.EMD.Sift+-- Copyright   : (c) Justin Le 2019+-- License     : BSD3+--+-- Maintainer  : justin@jle.im+-- Stability   : experimental+-- Portability : non-portable+--+-- Tools for creating your own custom sift stopping conditions.+--+-- @since 0.2.0.0+module Numeric.EMD.Sift (+    Sifter(..), SiftResult(..), SingleSift(..), SM+  -- * Sifters+  , defaultSifter+  , siftStdDev+  , siftTimes+  , siftEnergyDiff+  , siftSCond+  , siftAnd+  , siftOr+  -- ** Make Sifters+  , envMean+  , energyDiff+  , normalizeProj+  , siftCauchy+  , siftPairs+  , siftProj+  , siftPairs_+  , siftProj_+  -- * Internal+  , sift, envelopes, rms+  ) where++import           Control.Monad+import           Control.Monad.Trans.Class+import           Control.Monad.Trans.Reader+import           Control.Monad.Trans.State+import           Data.Conduino+import           Data.Conduino.Internal+import           Data.Default.Class+import           Data.Finite+import           Data.Sequence                (Seq(..))+import           GHC.TypeNats+import           Numeric.EMD.Internal+import           Numeric.EMD.Internal.Extrema+import           Numeric.EMD.Internal.Spline+import qualified Data.Conduino.Combinators    as C+import qualified Data.Map                     as M+import qualified Data.Vector.Generic          as VG+import qualified Data.Vector.Generic.Sized    as SVG++-- | @since 0.1.3.0+instance (VG.Vector v a, Fractional a, Ord a) => Default (Sifter v n a) where+    def = defaultSifter++-- | Default 'Sifter'+--+-- @+-- defaultSifter = 'siftStdDev' 0.3 `siftOr` 'siftTimes' 50+-- @+--+-- R package uses @'siftTimes' 20@, Matlab uses no limit+defaultSifter :: (VG.Vector v a, Fractional a, Ord a) => Sifter v n a+defaultSifter = siftStdDev 0.3 `siftOr` siftTimes 50++-- | Cheng, Yu, Yang suggest pairing together an energy difference+-- threshold with a threshold for mean envelope RMS.  This is a convenience+-- function to construct that pairing.+siftEnergyDiff+    :: (VG.Vector v a, KnownNat n, Floating a, Ord a)+    => a                -- ^ Threshold for Energy Difference+    -> a                -- ^ Threshold for mean envelope RMS+    -> Sifter v n a+siftEnergyDiff s t = siftProj energyDiff s+           `siftAnd` siftProj envMean t+++-- | The result of a sifting operation.  Each sift either yields+-- a residual, or a new IMF.+data SiftResult v n a = SRResidual !(SVG.Vector v n a)+                      | SRIMF      !(SVG.Vector v n a) !Int   -- ^ number of sifting iterations++-- | Create a sifter that stops after a given fixed number of sifts.+--+-- Useful to use alongside 'siftOr' to set an "upper limit" on the number+-- of sifts.+siftTimes :: Int -> Sifter v n a+siftTimes n = Sifter $ C.drop (n - 1) >> void awaitSurely++-- | Create a sifter that stops when some projection on 'SingleSift' is+-- smaller than a given threshold.+siftProj+    :: Ord b+    => (SingleSift v n a -> SM v n a b)     -- ^ projection+    -> b                                    -- ^ threshold+    -> Sifter v n a+siftProj p t = siftProj_ $ fmap (<= t) . p++-- | Create a sifter that stops based on some predicate on the initial+-- vector and 'SingleSift' being 'True'.+siftProj_ :: (SingleSift v n a -> SM v n a Bool) -> Sifter v n a+siftProj_ p = Sifter go+  where+    go = do+      v <- awaitSurely+      r <- lift $ p v+      unless r go++-- | Create a sifter that stops when some projection on two consecutive+-- 'SingleSift's is smaller than a given threshold.+siftPairs+    :: Ord b+    => (SingleSift v n a -> SingleSift v n a -> SM v n a b)+    -> b+    -> Sifter v n a+siftPairs p t = siftPairs_ $ \x y -> (<= t) <$> p x y++-- | Create a sifter that stops based on some predicate on two consecutive+-- 'SingleSift's being 'True'.+siftPairs_+    :: (SingleSift v n a -> SingleSift v n a -> SM v n a Bool)+    -> Sifter v n a+siftPairs_ p = Sifter $ go =<< awaitSurely+  where+    go s = do+      s' <- awaitSurely+      r  <- lift $ p s s'+      unless r (go s')++-- | Sift based on the "standard deviation test", outlined in original+-- paper.+siftStdDev+    :: forall v n a. (VG.Vector v a, Fractional a, Ord a)+    => a                -- ^ minimal threshold+    -> Sifter v n a+siftStdDev = siftPairs $ \(SingleSift v _ _) (SingleSift v' _ _) -> pure $+    SVG.sum (SVG.zipWith (\x x' -> (x-x')^(2::Int) / (x^(2::Int) + eps)) v v')+  where+    eps = 0.0000001++-- | General class of "cauchy-like" sifters: Given a projection function+-- from a 'SingleSift', stop as soon as successive projections become+-- smaller than a given threshold, propertionally.+--+-- Given \(f(x_t)\), stop when:+--+-- \[+--   \frac{(f(x_t) - f(x_{t-1}))^2}{f^2(x_{t-1})} < \delta+-- \]+siftCauchy+    :: (Fractional b, Ord b)+    => (SingleSift v n a -> b)      -- ^ Projection function+    -> b                            -- ^ Threshold \(\delta\)+    -> Sifter v n a+siftCauchy p = siftPairs $ \s s' ->+  let ps  = p s+      ps' = p s'+      δ   = ps' - ps+  in  pure $ (δ * δ) / (ps * ps)++-- | Sift based on the "S-parameter" condition: Stop after a streak @n@ of+-- almost-same numbers of zero crossings and turning points.+siftSCond+    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)+    => Int                          -- ^ Streak @n@ to stop on+    -> Sifter v (n + 1) a+siftSCond n = Sifter $ C.map (crossCount . ssResult)+                    .| C.consecutive n+                    .| C.concatMap pick+                    .| C.dropWhile notGood+  where+    pick Empty      = Nothing+    pick (xs :|> x) = (xs, x) <$ guard (length xs == (n - 1))+    notGood (xs, x) = all ((<= 1) . abs . subtract x) xs+    crossCount xs = M.size mins + M.size maxs + crosses+      where+        (mins, maxs) = extrema xs+        crosses = fst . flip execState (0, Nothing) . flip SVG.mapM_ xs $ \x -> modify $ \(!i, !y) ->+          let xPos = x > 0+              i'   = case y of+                       Nothing -> i+                       Just y'+                         | xPos == y' -> i+                         | otherwise  -> i + 1+          in  (i', Just xPos)++-- | Combine two sifters in "or" fashion: The final sifter will complete+-- when /either/ sifter completes.+siftOr :: Sifter v n a -> Sifter v n a -> Sifter v n a+siftOr (Sifter p) (Sifter q) = Sifter $ altSink p q+infixr 2 `siftOr`++-- | Combine two sifters in "and" fashion: The final sifter will complete+-- when /both/ sifters complete.+siftAnd :: Sifter v n a -> Sifter v n a -> Sifter v n a+siftAnd (Sifter p) (Sifter q) = Sifter $ zipSink (id <$ p) q+infixr 3 `siftAnd`++-- | Project the root mean square of the mean of the maximum and minimum+-- envelopes.+envMean+    :: (VG.Vector v a, KnownNat n, Floating a)+    => SingleSift v n a+    -> SM v n a a+envMean SingleSift{..} = pure $+    rms $ SVG.zipWith (\x y -> (x + y) / 2) ssMinEnv ssMaxEnv++-- | Project the /square root/ of the "Energy difference".+energyDiff+    :: (VG.Vector v a, Floating a)+    => SingleSift v n a+    -> SM v n a a+energyDiff SingleSift{..} = do+    v0 <- ask+    pure . sqrt . abs . SVG.sum+         $ SVG.zipWith (\x c -> c * (x - c)) v0 ssResult++-- | Given a "projection function" (like 'envMean' or 'energyDiff'),+-- re-scale the result based on the RMS of the original signal.+normalizeProj+    :: (VG.Vector v a, KnownNat n, Floating a)+    => (SingleSift v n a -> SM v n a a)+    -> (SingleSift v n a -> SM v n a a)+normalizeProj f ss = do+    v0 <- asks rms+    r  <- f ss+    pure $ r / v0++-- | Get the root mean square of a vector+rms :: (VG.Vector v a, KnownNat n, Floating a) => SVG.Vector v n a -> a+rms xs = sqrt $ SVG.foldl' (\s x -> s + x*x) 0 xs / fromIntegral (SVG.length xs)+++-- | Iterated sifting process, used to produce either an IMF or a residual.+sift+    :: forall v n a. (VG.Vector v a, KnownNat n, Floating a, Ord a)+    => EMDOpts v (n + 1) a+    -> SVG.Vector v (n + 1) a+    -> SiftResult v (n + 1) a+sift EO{..} v0 = case execStateT (runPipe sifterPipe) (0, v0) of+    Left  v        -> SRResidual v+    Right (!i, !v) -> SRIMF v i+  where+    sifterPipe = C.repeatM go+              .| hoistPipe+                    (pure . (`runReader` v0))+                    (sPipe eoSifter)+    go = StateT $ \(!i, !v) ->+      case sift' eoSplineEnd eoBoundaryHandler v of+        Nothing                -> Left v+        Just ss@SingleSift{..} -> Right (ss, (i + 1, ssResult))++-- | Single sift+sift'+    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)+    => SplineEnd a+    -> Maybe BoundaryHandler+    -> SVG.Vector v (n + 1) a+    -> Maybe (SingleSift v (n + 1) a)+sift' se bh v = do+    (mins, maxs) <- envelopes se bh v+    pure SingleSift+      { ssResult = SVG.zipWith3 (\x mi ma -> x - (mi + ma)/2) v mins maxs+      , ssMinEnv = mins+      , ssMaxEnv = maxs+      }++-- | Returns cubic splines of local minimums and maximums.  Returns+-- 'Nothing' if there are not enough local minimum or maximums to create+-- the splines.+envelopes+    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)+    => SplineEnd a+    -> Maybe BoundaryHandler+    -> SVG.Vector v (n + 1) a+    -> Maybe (SVG.Vector v (n + 1) a, SVG.Vector v (n + 1) a)+envelopes se bh xs = do+    when (bh == Just BHClamp) $ do+      guard (M.size mins > 1)+      guard (M.size maxs > 1)+    (,) <$> splineAgainst se emin mins+        <*> splineAgainst se emax maxs+  where+    -- minMax = M.fromList [(minBound, SVG.head xs), (maxBound, SVG.last xs)]+    (mins,maxs) = extrema xs+    (emin,emax) = case bh of+      Nothing  -> mempty+      Just bh' -> extendExtrema xs bh' (mins,maxs)+    --   | isJust bh = (mins `M.union` minMax, maxs `M.union` minMax)+    --   | otherwise = (mins, maxs)++extendExtrema+    :: forall v n a. (VG.Vector v a, KnownNat n)+    => SVG.Vector v (n + 1) a+    -> BoundaryHandler+    -> (M.Map (Finite (n + 1)) a, M.Map (Finite (n + 1)) a)+    -> (M.Map Int a, M.Map Int a)+    -- (M.Map (Finite (n + 1)) a, M.Map (Finite (n + 1)) a)+extendExtrema xs = \case+    BHClamp     -> const (firstLast, firstLast)+    BHSymmetric -> \(mins, maxs) ->+      let addFirst = case (flippedMin, flippedMax) of+              (Nothing      , Nothing      ) -> mempty+              -- first point is local maximum+              (Just (_,mn)  , Nothing      ) -> (mn        , firstPoint)+              -- first point is local minimum+              (Nothing      , Just (_,mx)  ) -> (firstPoint, mx        )+              (Just (mni,mn), Just (mxi,mx))+                | mni < mxi                  -> (mn        , firstPoint)+                | otherwise                  -> (firstPoint, mx        )+            where+              flippedMin = flip fmap (M.lookupMin mins) $ \(minIx, minVal) ->+                (minIx, M.singleton (negate (fromIntegral minIx)) minVal)+              flippedMax = flip fmap (M.lookupMin maxs) $ \(maxIx, maxVal) ->+                (maxIx, M.singleton (negate (fromIntegral maxIx)) maxVal)+          addLast = case (flippedMin, flippedMax) of+              (Nothing      , Nothing      ) -> mempty+              -- last point is local maximum+              (Just (_,mn)  , Nothing      ) -> (mn        , lastPoint )+              -- last point is local minimum+              (Nothing      , Just (_,mx)  ) -> (lastPoint , mx        )+              (Just (mni,mn), Just (mxi,mx))+                | mni > mxi                  -> (mn        , lastPoint )+                | otherwise                  -> (lastPoint , mx        )+            where+              flippedMin = flip fmap (M.lookupMax mins) $ \(minIx, minVal) ->+                (minIx, M.singleton (extendSym (fromIntegral minIx)) minVal)+              flippedMax = flip fmap (M.lookupMax maxs) $ \(maxIx, maxVal) ->+                (maxIx, M.singleton (extendSym (fromIntegral maxIx)) maxVal)+      in  addFirst `mappend` addLast+  where+    lastIx = fromIntegral $ maxBound @(Finite n)+    firstPoint = M.singleton 0 (SVG.head xs)+    lastPoint  = M.singleton lastIx (SVG.last xs)+    firstLast  = firstPoint `mappend` lastPoint+    extendSym i = 2 * lastIx - i++-- | Build a splined vector against a map of control points.+splineAgainst+    :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)+    => SplineEnd a+    -> M.Map Int a              -- ^ extensions+    -> M.Map (Finite n) a+    -> Maybe (SVG.Vector v n a)+splineAgainst se ext = fmap go+                     . makeSpline se+                     . mappend (M.mapKeysMonotonic fromIntegral ext)+                     . M.mapKeysMonotonic fromIntegral+  where+    go spline = SVG.generate (sampleSpline spline . fromIntegral)
src/Numeric/HHT.hs view
@@ -14,7 +14,7 @@  -- | -- Module      : Numeric.HHT--- Copyright   : (c) Justin Le 2018+-- Copyright   : (c) Justin Le 2019 -- License     : BSD3 -- -- Maintainer  : justin@jle.im@@ -43,7 +43,7 @@   , expectedFreq, dominantFreq   , foldFreq   -- ** Options-  , EMDOpts(..), defaultEO, BoundaryHandler(..), SiftCondition(..), defaultSC, SplineEnd(..)+  , EMDOpts(..), defaultEO, BoundaryHandler(..), defaultSifter, SplineEnd(..)   -- * Hilbert transforms (internal usage)   , hilbert   , hilbertIm@@ -125,7 +125,7 @@ -- Essentially is a composition of 'hhtEmd' and 'emd'.  See 'hhtEmd' for -- a more flexible version. hht :: forall v n a. (VG.Vector v a, VG.Vector v (Complex a), KnownNat n, FFT.FFTWReal a)-    => EMDOpts a+    => EMDOpts v (n + 1) a     -> SVG.Vector v (n + 1) a     -> HHT v n a hht eo = hhtEmd . emd eo
test/Tests/EMD.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE RankNTypes                               #-} {-# LANGUAGE ScopedTypeVariables                      #-} {-# LANGUAGE TemplateHaskell                          #-} {-# LANGUAGE TypeApplications                         #-}@@ -16,8 +17,10 @@ import           GHC.TypeNats import           Hedgehog import           Numeric.EMD+import           Numeric.EMD.Sift import           Test.Tasty import           Tests.Util+import qualified Data.Vector           as UV import qualified Hedgehog.Range        as Range  emdTests :: TestTree@@ -29,10 +32,10 @@ prop_orthog_default :: Property prop_orthog_default = orthogProp defaultEO -edtEO :: EMDOpts Double-edtEO = defaultEO-    { eoSiftCondition = scEnergyDiff 0.01 0.01-                 `SCOr` SCTimes 100+edtEO :: KnownNat n => EMDOpts UV.Vector n Double+edtEO = (defaultEO @UV.Vector)+    { eoSifter = siftEnergyDiff 0.01 0.01+        `siftOr` siftTimes 100     }  prop_iemd_edt :: Property@@ -41,10 +44,10 @@ prop_orthog_edt :: Property prop_orthog_edt = orthogProp edtEO -sCondEO :: EMDOpts Double-sCondEO = defaultEO-    { eoSiftCondition = SCSCond 10-                 `SCOr` SCTimes 100+sCondEO :: KnownNat n => EMDOpts UV.Vector (n + 1) Double+sCondEO = (defaultEO @UV.Vector)+    { eoSifter = siftSCond 10+        `siftOr` siftTimes 100     }  prop_iemd_sCond :: Property@@ -54,12 +57,12 @@ prop_orthog_sCond = orthogProp sCondEO  -iemdProp :: EMDOpts Double -> Property+iemdProp :: (forall n. KnownNat n => EMDOpts UV.Vector (n + 1) Double) -> Property iemdProp eo = property $ withSize (Range.linear 1 8) $ \(_ :: Proxy n) -> do     xs <- forAll $ generateData @n     tripping (CE xs) (emd @_ @_ @(2^n-1) eo . getCE) (Identity . CE . iemd) -orthogProp :: EMDOpts Double -> Property+orthogProp :: (forall n. KnownNat n => EMDOpts UV.Vector (n + 1) Double) -> Property orthogProp eo = property $ withSize (Range.linear 8 10) $ \(_ :: Proxy n) -> do     xs   <- forAll $ generateData @n     let imfs = emdIMFs (emd @_ @_ @(2^n-1) eo xs)