diff --git a/yampa-test/CHANGELOG b/yampa-test/CHANGELOG index 800cb23..283c9ba 100644 --- a/yampa-test/CHANGELOG +++ b/yampa-test/CHANGELOG @@ -1,3 +1,7 @@ +2024-08-07 Ivan Perez + * Version bump (0.14.10) (#302). + * Add test for trapezoidIntegral (#263). + 2024-06-08 Ivan Perez * Version bump (0.14.9) (#299). diff --git a/yampa-test/tests/Test/FRP/Yampa/Integration.hs b/yampa-test/tests/Test/FRP/Yampa/Integration.hs index 0220e70..ad63cb5 100644 --- a/yampa-test/tests/Test/FRP/Yampa/Integration.hs +++ b/yampa-test/tests/Test/FRP/Yampa/Integration.hs @@ -27,6 +27,8 @@ tests = testGroup "Regression tests for FRP.Yampa.Integration" , testProperty "imIntegral (0, qc)" testImIntegral0 , testProperty "imIntegral (1, qc)" testImIntegral1 , testProperty "imIntegral (2, qc)" testImIntegral2 + , testProperty "trapezoidIntegral (0, qc)" testTrapezoidIntegral0 + , testProperty "trapezoidIntegral (1, qc)" testTrapezoidIntegral1 , testProperty "impulseIntegral (0, fixed)" (property $ utils_t7 ~= utils_t7r) , testProperty "count (0, fixed)" (property $ utils_t4 ~= utils_t4r) , testProperty "count (1, fixed)" (property $ utils_t5 ~= utils_t5r) @@ -149,6 +151,40 @@ testImIntegral2 = close (x,y) = abs (x-y) < 0.05 +testTrapezoidIntegral0 :: Property +testTrapezoidIntegral0 = + forAll myStream $ evalT $ + Next $ Always $ prop ((sf &&& sfByHand), const close) + + where + myStream :: Gen (SignalSampleStream Double) + myStream = uniDistStream + + sf :: SF Double Double + sf = trapezoidIntegral >>> derivative + + sfByHand :: SF Double Double + sfByHand = (identity &&& iPre 0) >>^ (\(x, y) -> (x + y) / 2) + + close (x,y) = abs (x-y) < 0.05 + +testTrapezoidIntegral1 :: Property +testTrapezoidIntegral1 = + forAll myStream $ evalT $ + Next $ Always $ prop ((sf &&& sfByHand), const close) + + where + myStream :: Gen (SignalSampleStream Double) + myStream = uniDistStream + + sf :: SF Double Double + sf = arr (*2) >>> trapezoidIntegral + + sfByHand :: SF Double Double + sfByHand = trapezoidIntegral >>> arr (*2) + + close (x,y) = abs (x-y) < 0.05 + utils_t7 :: [Double] utils_t7 = take 50 $ embed impulseIntegral (deltaEncode 0.1 (zip (repeat 1.0) evSeq)) diff --git a/yampa-test/yampa-test.cabal b/yampa-test/yampa-test.cabal index 4a69d2e..4227347 100644 --- a/yampa-test/yampa-test.cabal +++ b/yampa-test/yampa-test.cabal @@ -31,7 +31,7 @@ cabal-version: >= 1.10 build-type: Simple name: yampa-test -version: 0.14.9 +version: 0.14.10 author: Ivan Perez maintainer: ivan.perez@keera.co.uk homepage: http://github.com/ivanperez-keera/Yampa @@ -84,7 +84,7 @@ library base >= 4 && < 5 , normaldistribution >= 1.1.0.1 && < 1.2 , QuickCheck >= 2.12 && < 2.15 - , Yampa >= 0.14.9 && < 0.15 + , Yampa >= 0.14.10 && < 0.15 default-language: Haskell2010 diff --git a/yampa/CHANGELOG b/yampa/CHANGELOG index 60852a0..ef629cf 100644 --- a/yampa/CHANGELOG +++ b/yampa/CHANGELOG @@ -1,3 +1,7 @@ +2024-08-07 Ivan Perez + * Version bump (0.14.10) (#302). + * Implement integral using trapezoid rule (#263). + 2024-06-08 Ivan Perez * Version bump (0.14.9) (#299). * Document FRP.Yampa.Random.streamToSF (#296). diff --git a/yampa/Yampa.cabal b/yampa/Yampa.cabal index 9d7c0ef..dc533dc 100644 --- a/yampa/Yampa.cabal +++ b/yampa/Yampa.cabal @@ -30,7 +30,7 @@ cabal-version: >= 1.10 build-type: Simple name: Yampa -version: 0.14.9 +version: 0.14.10 author: Henrik Nilsson, Antony Courtney maintainer: Ivan Perez (ivan.perez@keera.co.uk) homepage: https://github.com/ivanperez-keera/Yampa/ diff --git a/yampa/src/FRP/Yampa.hs b/yampa/src/FRP/Yampa.hs index 785eb71..c3fb6ea 100644 --- a/yampa/src/FRP/Yampa.hs +++ b/yampa/src/FRP/Yampa.hs @@ -280,6 +280,7 @@ module FRP.Yampa -- ** Integration and differentiation , integral , imIntegral + , trapezoidIntegral , impulseIntegral , count , derivative diff --git a/yampa/src/FRP/Yampa/Integration.hs b/yampa/src/FRP/Yampa/Integration.hs index 99413bd..e5fe2bd 100644 --- a/yampa/src/FRP/Yampa/Integration.hs +++ b/yampa/src/FRP/Yampa/Integration.hs @@ -32,6 +32,7 @@ module FRP.Yampa.Integration -- * Integration integral , imIntegral + , trapezoidIntegral , impulseIntegral , count @@ -71,6 +72,12 @@ integral = SF {sfTF = tf0} imIntegral :: (Fractional s, VectorSpace a s) => a -> SF a a imIntegral = ((\_ a' dt v -> v ^+^ realToFrac dt *^ a') `iterFrom`) +-- | Trapezoid integral (using the average between the value at the last time +-- and the value at the current time). +trapezoidIntegral :: (Fractional s, VectorSpace a s) => SF a a +trapezoidIntegral = + iterFrom (\a a' dt v -> v ^+^ (realToFrac dt / 2) *^ (a ^+^ a')) zeroVector + -- | Integrate the first input signal and add the /discrete/ accumulation (sum) -- of the second, discrete, input signal. impulseIntegral :: (Fractional k, VectorSpace a k) => SF (a, Event a) a