{-# LANGUAGE GADTs, Rank2Types, CPP #-} ----------------------------------------------------------------------------------------- -- | -- Module : FRP.Yampa.Random -- Copyright : (c) Antony Courtney and Henrik Nilsson, Yale University, 2003 -- License : BSD-style (see the LICENSE file in the distribution) -- -- Maintainer : ivan.perez@keera.co.uk -- Stability : provisional -- Portability : non-portable (GHC extensions) -- -- Signals and signal functions with noise and randomness. -- -- The Random number generators are re-exported from "System.Random". ----------------------------------------------------------------------------------------- module FRP.Yampa.Random ( -- * Random number generators RandomGen(..), Random(..), -- * Noise, random signals, and stochastic event sources noise, -- :: noise :: (RandomGen g, Random b) => -- g -> SF a b noiseR, -- :: noise :: (RandomGen g, Random b) => -- (b,b) -> g -> SF a b occasionally, -- :: RandomGen g => g -> Time -> b -> SF a (Event b) ) where import System.Random (RandomGen(..), Random(..)) import FRP.Yampa.InternalCore (SF(..), SF'(..), Time) import FRP.Yampa.Diagnostics import FRP.Yampa.Event ------------------------------------------------------------------------------ -- Noise (i.e. random signal generators) and stochastic processes ------------------------------------------------------------------------------ -- | Noise (random signal) with default range for type in question; -- based on "randoms". noise :: (RandomGen g, Random b) => g -> SF a b noise g0 = streamToSF (randoms g0) -- | Noise (random signal) with specified range; based on "randomRs". noiseR :: (RandomGen g, Random b) => (b,b) -> g -> SF a b noiseR range g0 = streamToSF (randomRs range g0) -- Internal. Not very useful for other purposes since we do not have any -- control over the intervals between each "sample". Or? A version with -- time-stamped samples would be similar to embedSynch (applied to identity). -- The list argument must be a stream (infinite list) at present. streamToSF :: [b] -> SF a b streamToSF [] = intErr "AFRP" "streamToSF" "Empty list!" streamToSF (b:bs) = SF {sfTF = tf0} where tf0 _ = (stsfAux bs, b) stsfAux [] = intErr "AFRP" "streamToSF" "Empty list!" -- Invarying since stsfAux [] is an error. stsfAux (b:bs) = SF' tf -- True where tf _ _ = (stsfAux bs, b) {- New def, untested: streamToSF = sscan2 f where f [] _ = intErr "AFRP" "streamToSF" "Empty list!" f (b:bs) _ = (bs, b) -} -- | Stochastic event source with events occurring on average once every t_avg -- seconds. However, no more than one event results from any one sampling -- interval in the case of relatively sparse sampling, thus avoiding an -- "event backlog" should sampling become more frequent at some later -- point in time. -- !!! Maybe it would better to give a frequency? But like this to make -- !!! consitent with "repeatedly". occasionally :: RandomGen g => g -> Time -> b -> SF a (Event b) occasionally g t_avg x | t_avg > 0 = SF {sfTF = tf0} | otherwise = usrErr "AFRP" "occasionally" "Non-positive average interval." where -- Generally, if events occur with an average frequency of f, the -- probability of at least one event occurring in an interval of t -- is given by (1 - exp (-f*t)). The goal in the following is to -- decide whether at least one event occurred in the interval of size -- dt preceding the current sample point. For the first point, -- we can think of the preceding interval as being 0, implying -- no probability of an event occurring. tf0 _ = (occAux (randoms g :: [Time]), NoEvent) occAux [] = undefined occAux (r:rs) = SF' tf -- True where tf dt _ = let p = 1 - exp (-(dt/t_avg)) -- Probability for at least one event. in (occAux rs, if r < p then Event x else NoEvent) -- Vim modeline -- vim:set tabstop=8 expandtab: