-- |-- Module: Control.Wire.Prefab.Analyze-- Copyright: (c) 2011 Ertugrul Soeylemez-- License: BSD3-- Maintainer: Ertugrul Soeylemez <es@ertes.de>---- Various signal analysis toolsmoduleControl.Wire.Prefab.Analyze(-- * Statistics-- ** Averageavg,avgAll,avgFps,-- ** PeakhighPeak,lowPeak,peakBy,-- * Monitoringcollect,diff,firstSeen,lastSeen)whereimportqualifiedData.MapasMimportqualifiedData.SetasSimportqualifiedData.Vector.UnboxedasVuimportqualifiedData.Vector.Unboxed.MutableasVumimportControl.ArrowimportControl.Monad.FiximportControl.Monad.STimportControl.Wire.ClassesimportControl.Wire.Prefab.ClockimportControl.Wire.TypesimportData.Map(Map)importData.MonoidimportData.Set(Set)-- | Calculate the average of the signal over the given number of last-- samples. If you need an average over all samples ever produced,-- consider using 'avgAll' instead.---- * Complexity: O(n) space, O(1) time wrt number of samples.---- * Depends: current instant.avg::forallev(>~).(Arrow(>~),Fractionalv,Vu.Unboxv)=>Int->Wiree(>~)vvavgn=mkPure$\x->(Rightx,avg'(Vu.replicaten(x/d))x0)whereavg'::Vu.Vectorv->v->Int->Wiree(>~)vvavg'samples's'cur'=mkPure$\((/d)->x)->letcur=letcur=succcur'inifcur>=nthen0elsecurx'=samples'Vu.!cursamples=x'`seq`runST$dos<-Vu.unsafeThawsamples'Vum.writescurxVu.unsafeFreezess=s'-x'+xincur`seq`s'`seq`(Rights,avg'samplesscur)d::vd=realToFracn-- | Calculate the average of the signal over all samples.---- Please note that somewhat surprisingly this wire runs in constant-- space and is generally faster than 'avg', but most applications will-- benefit from averages over only the last few samples.---- * Depends: current instant.avgAll::forallev(>~).(Arrow(>~),Fractionalv)=>Wiree(>~)vvavgAll=mkPure$\x->(Rightx,avgAll'1x)whereavgAll'::v->v->Wiree(>~)vvavgAll'n'a'=mkPure$\x->letn=n'+1a=a'-a'/n+x/nina'`seq`(Righta,avgAll'na)-- | Calculate the average number of frames per virtual second for the-- last given number of frames.---- Please note that this wire uses the clock from the 'ArrowClock'-- instance for the underlying arrow. If this clock doesn't represent-- real time, then the output of this wire won't either.avgFps::(ArrowChoice(>~),ArrowClock(>~),Fractionalt,Time(>~)~t,Vu.Unboxt)=>Int->Wiree(>~)atavgFpsn=recip^<<avgn<<<dtime-- | Collects all distinct inputs ever received.---- * Complexity: O(n) space, O(log n) time wrt collected inputs so far.---- * Depends: current instant.collect::forallbe(>~).Ordb=>Wiree(>~)b(Setb)collect=collect'S.emptywherecollect'::Setb->Wiree(>~)b(Setb)collect'ins'=mkPure$\x->letins=S.insertxins'in(Rightins,collect'ins)-- | Outputs the last input value on every change of the input signal.-- Acts like the identity wire at the first instant.---- * Depends: current instant.---- * Inhibits: on no change after the first instant.diff::forallbe(>~).(Eqb,Monoide)=>Wiree(>~)bbdiff=mkPure$\x->(Rightx,diff'x)wherediff'::b->Wiree(>~)bbdiff'x'=mkPure$\x->ifx'==xthen(Leftmempty,diff'x')else(Rightx',diff'x)-- | Reports the first time the given input was seen.---- * Complexity: O(n) space, O(log n) time wrt collected inputs so far.---- * Depends: Current instant.firstSeen::forallaet(>~).(ArrowChoice(>~),ArrowClock(>~),Monoide,Orda,Time(>~)~t)=>Wiree(>~)atfirstSeen=firstSeen'M.emptywherefirstSeen'::Mapat->Wiree(>~)atfirstSeen'xs'=fix$\again->mkGen$procx'->docaseM.lookupx'xs'ofJustt->returnA-<(Rightt,again)Nothing->dot<-arrTime-<()returnA-<(Rightt,firstSeen'(M.insertx'txs'))-- | Outputs the high peak of the input signal.---- * Depends: Current instant.highPeak::Ordb=>Wiree(>~)bbhighPeak=peakBycompare-- | Reports the last time the given input was seen. Inhibits when-- seeing a signal for the first time.---- * Complexity: O(n) space, O(log n) time wrt collected inputs so far.---- * Depends: Current instant.---- * Inhibits: On first sight of a signal.lastSeen::forallaet(>~).(ArrowClock(>~),Monoide,Orda,Time(>~)~t)=>Wiree(>~)atlastSeen=lastSeen'M.emptywherelastSeen'::Mapat->Wiree(>~)atlastSeen'xs'=mkGen$procx'->dot<-arrTime-<()letxs=M.insertx'txs'returnA-<(maybe(Leftmempty)Right$M.lookupx'xs',lastSeen'xs)-- | Outputs the low peak of the input signal.---- * Depends: Current instant.lowPeak::Ordb=>Wiree(>~)bblowPeak=peakBy(flipcompare)-- | Outputs the high peak of the input signal with respect to the given-- comparison function.---- * Depends: Current instant.peakBy::forallbe(>~).(b->b->Ordering)->Wiree(>~)bbpeakBycomp=mkPure(Right&&&peakBy')wherepeakBy'::b->Wiree(>~)bbpeakBy'x''=mkPure$\x'->Right&&&peakBy'$ifcompx'x''==GTthenx'elsex''