packages feed

sdr-0.1.0.0: tests/TestSuite.hs

{-# LANGUAGE ScopedTypeVariables #-}

import           Control.Monad.Primitive 
import           Data.Complex

import qualified Data.Vector.Generic               as VG
import qualified Data.Vector.Generic.Mutable       as VGM
import qualified Data.Vector.Storable              as VS
import qualified Data.Vector.Storable.Mutable      as VSM

import           Test.QuickCheck
import           Test.QuickCheck.Monadic
import           Test.Framework (defaultMain, testGroup)
import           Test.Framework.Providers.QuickCheck2 (testProperty)

import           SDR.FilterInternal
import           SDR.Util

tests = [
        testGroup "filters" [
            testProperty "real"    propFiltersReal,
            testProperty "complex" propFiltersComplex
        ],
        testGroup "decimators" [
            testProperty "real"    propDecimationReal,
            testProperty "complex" propDecimationComplex
        ],
        testGroup "resamplers" [
            testProperty "real" propResamplingReal
        ],
        testProperty "conversion" propConversion,
        testProperty "scaling"    propScaleReal
    ]
    where
    sizes           = elements [1024, 2048, 4096, 8192, 16384, 32768, 65536]
    numCoeffs       = elements [32, 64, 128, 256, 512]
    factors         = elements [1, 2, 3, 4, 7, 9, 12, 15, 21]
    factors'        = [1, 2, 3, 4, 7, 9, 12, 15, 21]

    propFiltersReal = forAll sizes $ \size -> 
                          forAll (vectorOf size (choose (-10, 10))) $ \inBuf -> 
                              forAll numCoeffs $ \numCoeffs -> 
                                  forAll (vectorOf numCoeffs (choose (-10, 10))) $ \coeffs -> 
                                      testFiltersReal size numCoeffs coeffs inBuf

    testFiltersReal :: Int -> Int -> [Float] -> [Float] -> Property
    testFiltersReal size numCoeffs coeffs inBuf = monadicIO $ do
        let vCoeffsHalf = VS.fromList coeffs
            vCoeffs     = VS.fromList $ coeffs ++ reverse coeffs
            vInput      = VS.fromList inBuf
            num         = size - numCoeffs*2 + 1

        r1 <- run $ getResult num $ filterHighLevel       vCoeffs     num vInput
        r2 <- run $ getResult num $ filterImperative1     vCoeffs     num vInput
        r3 <- run $ getResult num $ filterImperative2     vCoeffs     num vInput
        r4 <- run $ getResult num $ filterCRR             vCoeffs     num vInput
        r5 <- run $ getResult num $ filterCSSERR          vCoeffs     num vInput
        r6 <- run $ getResult num $ filterCAVXRR          vCoeffs     num vInput
        r7 <- run $ getResult num $ filterCSSESymmetricRR vCoeffsHalf num vInput
        r8 <- run $ getResult num $ filterCAVXSymmetricRR vCoeffsHalf num vInput

        assert $ and $ map (r1 `eqDelta`) [r2, r3, r4, r5, r6, r7, r8]

    propFiltersComplex = forAll sizes $ \size -> 
                             forAll (vectorOf size (choose (-10, 10))) $ \inBufR -> 
                                 forAll (vectorOf size (choose (-10, 10))) $ \inBufI -> 
                                     forAll numCoeffs $ \numCoeffs -> 
                                         forAll (vectorOf numCoeffs (choose (-10, 10))) $ \coeffs -> 
                                             testFiltersComplex size numCoeffs coeffs $ zipWith (:+) inBufR inBufI

    testFiltersComplex :: Int -> Int -> [Float] -> [Complex Float] -> Property
    testFiltersComplex size numCoeffs coeffs inBuf = monadicIO $ do
        let vCoeffsHalf = VS.fromList coeffs
            vCoeffs     = VS.fromList $ coeffs ++ reverse coeffs
            vInput      = VS.fromList inBuf
            num         = size - numCoeffs*2 + 1
            vCoeffs2    = VG.fromList $ duplicate $ coeffs ++ reverse coeffs

        r1 <- run $ getResult num $ filterHighLevel       vCoeffs  num vInput
        r2 <- run $ getResult num $ filterCRC             vCoeffs  num vInput
        r3 <- run $ getResult num $ filterCSSERC          vCoeffs2 num vInput
        r4 <- run $ getResult num $ filterCSSERC2         vCoeffs  num vInput
        r5 <- run $ getResult num $ filterCAVXRC          vCoeffs2 num vInput
        r6 <- run $ getResult num $ filterCSSESymmetricRC vCoeffsHalf num vInput
        r7 <- run $ getResult num $ filterCAVXSymmetricRC vCoeffsHalf num vInput

        assert $ and $ map (r1 `eqDeltaC`) [r2, r3, r4, r5, r6, r7]

    propDecimationReal = forAll sizes $ \size -> 
                             forAll (vectorOf size (choose (-10, 10))) $ \inBuf -> 
                                 forAll numCoeffs $ \numCoeffs -> 
                                     forAll (vectorOf numCoeffs (choose (-10, 10))) $ \coeffs -> 
                                        forAll factors $ \factor -> 
                                             testDecimationReal size numCoeffs factor coeffs inBuf

    testDecimationReal :: Int -> Int -> Int -> [Float] -> [Float] -> Property
    testDecimationReal size numCoeffs factor coeffs inBuf = monadicIO $ do
        let vCoeffsHalf = VS.fromList coeffs
            vCoeffs     = VS.fromList $ coeffs ++ reverse coeffs
            vInput      = VS.fromList inBuf
            num         = (size - numCoeffs*2 + 1) `quot` factor

        r1 <- run $ getResult num $ decimateHighLevel       factor vCoeffs     num vInput
        r2 <- run $ getResult num $ decimateCRR             factor vCoeffs     num vInput
        r3 <- run $ getResult num $ decimateCSSERR          factor vCoeffs     num vInput
        r4 <- run $ getResult num $ decimateCAVXRR          factor vCoeffs     num vInput
        r5 <- run $ getResult num $ decimateCSSESymmetricRR factor vCoeffsHalf num vInput
        r6 <- run $ getResult num $ decimateCAVXSymmetricRR factor vCoeffsHalf num vInput

        assert $ and $ map (r1 `eqDelta`) [r2, r3, r4, r5, r6]

    propDecimationComplex = forAll sizes $ \size -> 
                                forAll (vectorOf size (choose (-10, 10))) $ \inBufR -> 
                                    forAll (vectorOf size (choose (-10, 10))) $ \inBufI -> 
                                        forAll numCoeffs $ \numCoeffs -> 
                                            forAll (vectorOf numCoeffs (choose (-10, 10))) $ \coeffs -> 
                                                forAll factors $ \factor -> 
                                                    testDecimationComplex size numCoeffs factor coeffs $ zipWith (:+) inBufR inBufI

    testDecimationComplex :: Int -> Int -> Int -> [Float] -> [Complex Float] -> Property
    testDecimationComplex size numCoeffs factor coeffs inBuf = monadicIO $ do
        let vCoeffsHalf = VS.fromList coeffs
            vCoeffs     = VS.fromList $ coeffs ++ reverse coeffs
            vInput      = VS.fromList inBuf
            num         = (size - numCoeffs*2 + 1) `quot` factor
            vCoeffs2    = VG.fromList $ duplicate $ coeffs ++ reverse coeffs

        r1 <- run $ getResult num $ decimateHighLevel       factor vCoeffs  num vInput
        r2 <- run $ getResult num $ decimateCRC             factor vCoeffs  num vInput
        r3 <- run $ getResult num $ decimateCSSERC          factor vCoeffs2 num vInput
        r4 <- run $ getResult num $ decimateCSSERC2         factor vCoeffs  num vInput
        r5 <- run $ getResult num $ decimateCAVXRC          factor vCoeffs2 num vInput
        r6 <- run $ getResult num $ decimateCSSESymmetricRC factor vCoeffsHalf  num vInput
        r7 <- run $ getResult num $ decimateCAVXRC2         factor vCoeffs  num vInput
        r8 <- run $ getResult num $ decimateCAVXSymmetricRC factor vCoeffsHalf  num vInput

        assert $ and $ map (r1 `eqDeltaC`) [r2, r3, r4, r5, r6, r7, r8]

    propResamplingReal = forAll sizes $ \size -> 
                             forAll (vectorOf size (choose (-10, 10))) $ \inBuf -> 
                                 forAll numCoeffs $ \numCoeffs -> 
                                     forAll (vectorOf numCoeffs (choose (-10, 10))) $ \coeffs -> 
                                        forAll (elements $ tail factors') $ \decimation -> 
                                            forAll (elements $ filter (< decimation) factors') $ \interpolation -> 
                                                 testResamplingReal size numCoeffs interpolation decimation coeffs inBuf

    testResamplingReal :: Int -> Int -> Int -> Int -> [Float] -> [Float] -> Property
    testResamplingReal size numCoeffs interpolation decimation coeffs inBuf = monadicIO $ do
        let vCoeffsHalf = VS.fromList coeffs
            vCoeffs     = VS.fromList $ coeffs ++ reverse coeffs
            vInput      = VS.fromList inBuf
            num         = (size - numCoeffs*2 + 1) `quot` decimation

        resampler3 <- run $ resampleCRR2   interpolation decimation (coeffs ++ reverse coeffs)
        resampler4 <- run $ resampleCSSERR interpolation decimation (coeffs ++ reverse coeffs)
        resampler5 <- run $ resampleCAVXRR interpolation decimation (coeffs ++ reverse coeffs)

        r1 <- run $ getResult num $ resampleHighLevel       interpolation decimation vCoeffs 0 num vInput
        r2 <- run $ getResult num $ resampleCRR             num interpolation decimation 0 vCoeffs vInput
        r3 <- run $ getResult num $ resampler3              num 0 vInput
        r4 <- run $ getResult num $ resampler4              num 0 vInput
        r5 <- run $ getResult num $ resampler5              num 0 vInput

        assert $ and $ map (r1 `eqDelta`) [r2, r3, r4, r5]

    getResult :: (VSM.Storable a) => Int -> (VS.MVector RealWorld a -> IO b) -> IO [a]
    getResult size func = do
        outBuf <- VGM.new size
        func outBuf
        out :: VS.Vector a <- VG.freeze outBuf
        return $ VG.toList out

    propConversion = forAll sizes $ \size -> 
                         forAll (vectorOf (2 * size) (choose (-10, 10))) $ \inBuf -> 
                             testConversion size inBuf
    testConversion :: Int -> [Int] -> Property
    testConversion size inBuf = monadicIO $ do
        let vInput = VS.fromList $ map fromIntegral inBuf

        let r1 = VG.toList $ (makeComplexBufferVect vInput :: VS.Vector (Complex Float))
            r2 = VG.toList $ convertC              vInput
            r3 = VG.toList $ convertCSSE           vInput
            r4 = VG.toList $ convertCAVX           vInput

        assert $ and $ map (r1 `eqDeltaC`) [r2, r3, r4]

    scales          = elements [0.1, 0.5, 1, 2, 10]
    propScaleReal = forAll sizes $ \size -> 
                        forAll (vectorOf size (choose (-10, 10))) $ \inBuf -> 
                            forAll scales $ \factor -> 
                                testScaleReal size inBuf factor
    testScaleReal :: Int -> [Float] -> Float -> Property
    testScaleReal size inBuf factor = monadicIO $ do
        let vInput = VS.fromList inBuf

        r1 <- run $ getResult size $ scaleC    factor vInput
        r2 <- run $ getResult size $ scaleCSSE factor vInput
        r3 <- run $ getResult size $ scaleCAVX factor vInput

        assert $ and $ map (r1 `eqDelta`) [r2, r3]

    eqDelta x y = and $ map (uncurry eqDelta') $ zip x y
        where
        eqDelta' x y = abs (x - y) < 0.01
    eqDeltaC x y = and $ map (uncurry eqDelta') $ zip x y
        where
        eqDelta' x y = magnitude (x - y) < 0.01
    duplicate :: [a] -> [a]
    duplicate = concat . map func 
        where func x = [x, x]

main = defaultMain tests