{-# LANGUAGE TemplateHaskell, RelaxedPolyRec, PatternGuards #-} -- The PatternGuards are used to hush innapropiate compiler warnings -- see http://hackage.haskell.org/trac/ghc/ticket/2017 ----------------------------------------------------------------------------- -- | -- Module : ForSyDe.FIR -- Copyright : (c) SAM Group, KTH/ICT/ECS 2007-2008 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : forsyde-dev@ict.kth.se -- Stability : experimental -- Portability : portable -- -- This module implements FIR filters for the synchronous computational model. ----------------------------------------------------------------------------- module ForSyDe.FIR (fir) where import ForSyDe.Ids import ForSyDe.Signal import ForSyDe.Process import Data.TypeLevel.Num (Nat, Pos) import Data.Param.FSVec hiding ((++)) import qualified Data.Param.FSVec as V import Data.Typeable -- | -- All kinds of FIR-filters can now be modeled by means of 'fir'. The -- only argument needed is the list of coefficients, which is given as -- a vector of any size. To illustrate this, an 8-th order band pass -- filter is modeled as follows. -- -- > bp = fir "fir Id" $(vectorTH [0.06318761339784, 0.08131651217682, 0.09562326700432, -- > 0.10478344432968, 0.10793629404886, 0.10478344432968, -- > 0.09562326700432, 0.08131651217682, 0.06318761339784 ]) -- fir :: (Fractional b, ProcType b, Pos s, Typeable s) => ProcId -> FSVec s b -> Signal b -> Signal b fir id h = innerProd (id ++ "_innerProd") h . sipo (id ++ "_sipo") k 0.0 where k = V.lengthT h sipo :: (Pos s, Typeable s, Fractional a, ProcType a) => ProcId -> s -> a -> Signal a -> FSVec s (Signal a) sipo id n s0 = unzipxSY (id ++ "_unzipxSY") . scanldSY (id ++ "_scanldSY") srV initState where initState = V.copy n s0 srV = $(newProcFun [d| srV :: Pos s => FSVec s a -> a -> FSVec s a srV v a = V.shiftr v a |]) innerProd :: (Fractional a, ProcType a, Nat s, Typeable s) => ProcId -> FSVec s a -> FSVec s (Signal a) -> Signal a innerProd id h = zipWithxSY id (ipV `defArgVal` h) where ipV = $(newProcFun -- We could make the inner product in one traverse -- but FSVecs don't allow recursive calls -- (they don't allow to check the constraints statically) -- Thus, we traverse the vector twice [d| ipV :: (Nat s, Num a) => FSVec s a -> FSVec s a -> a ipV v1 v2 = V.foldl (+) 0 $ V.zipWith (*) v1 v2 |])