否则使用无香蕉一些基本演算(Doing some basic calculus using Reac

2019-06-28 00:51发布

设置

我使用的无功香蕉用OpenGL一起,我有我想要旋转的齿轮。 我有以下信号:

bTime :: Behavior t Int -- the time in ms from start of rendering
bAngularVelosity :: Behavior t Double -- the angular velocity
                                      -- which can be increase or
                                      -- decreased by the user
eDisplay :: Event t ()     -- need to redraw the screen
eKey :: Event t KeyState   -- user input

最后,我需要计算bAngle ,然后将其过去的绘图功能:

reactimate $ (draw gears) <$> (bAngle <@ eDisp)

的角度很容易计算: a = ∫v(t) dt

问题

我想要做的是在接近这个整体作为a = ∑ v Δt每个eDisplay事件(或更多的时候,如果我需要)。 这是去了解这个正确的方法是什么? 如果是这样,我怎么ΔtbTime

另请参见 :我怀疑答案使用mapAccum功能。 如果是这样,请另见我的其他问题也是如此。

Answer 1:

编辑:要回答这个问题,是的,你说得对使用您正在使用的逼近,这是解决一阶微分方程的欧拉法,是你的目的不够准确,特别是因为用户不具有对于角速度躺在身边判断你对绝对值。 减少你的时间间隔将使其更加准确,但是这并不重要。

您可以在更少的,更大的步骤(见下文)做到这一点,但这种方式似乎清楚的给我,我希望这是你。

为什么这个再解决烦恼呢? 这样,即使eDisplay发生在不规则的时间间隔,因为它计算eDeltaT

让我们给自己一个时间事件:

eTime :: Event t Int
eTime = bTime <@ eDisplay

为了得到DeltaT的,我们需要保持的时间间隔传递的轨迹:

type TimeInterval = (Int,Int) -- (previous time, current time)

所以我们可以将它们转换成三角洲:

delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0

我们应该如何更新的时间间隔,当我们得到一个新的t2

tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)

因此,让我们部分应用,为的时候,给我们的时间间隔更新:

eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime

然后我们可以accumE -accumulate上的初始时间间隔功能:

eTimeInterval :: Event t TimeInterval
eTimeInterval = accumE (0,0) eTicker

由于ETIME是因为呈现的开始时测量,初始(0,0)是适当的。

最后,我们可以有我们的DeltaT事件,只把它运用( fmap平) delta上的时间间隔。

eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval

现在,我们需要更新的角度,用类似的想法。

我会让角度更新,只需转动的bAngularVelocity成倍数:

bAngleMultiplier :: Behaviour t (Double->Double)
bAngleMultiplier = (*) <$> bAngularVelocity

那么我们就可以用它来使eDeltaAngle :(编辑:更改为(+)并转换为Double

eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> (bAngleMultiplier <@> ((fromInteger.toInteger) <$> eDeltaT)

和积累得到的角度:

eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle

如果你喜欢的俏皮话,你可以写

eDeltaT = delta <$> (accumE (0,0) $ tick <$> (bTime <@ eDisplay)) where
    delta (t0,t1) = t1 - t0
    tick t2 (t0,t1) = (t1,t2)

eAngle = accumE 0.0 $ (+) <$> ((*) <$> bAngularVelocity <@> eDeltaT) = 

但我不认为这非常具有启发性,说实话,我不知道我有我的固定性的权利,因为我没有在ghci中测试这一点。

当然,因为我做了eAngle代替bAngle ,你需要

reactimate $ (draw gears) <$> eAngle

而不是你原来的

reactimate $ (draw gears) <$> (bAngle <@ eDisp)


Answer 2:

一个简单的方法是假设eDisplay发生在固定的时间间隔,并考虑bAngularVelocity是一个相对的而不是绝对的措施,界河会给你下面真的相当短的解决方案。 [注意,这是没有好,如果eDisplay是失控的,或者如果它触发不定期明显,或规律性变化的,因为它会导致你的装备以不同的速度为您的间隔旋转eDisplay变化。 你需要我的其他(长)的办法,如果是这样的话。]

eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> bAngularVelocity <@ eDisplay

即转bAngularVelocity到加法器事件触发时你eDisplay ,所以后来

eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle

最后

reactimate $ (draw gears) <$> eAngle

是的,近似的积分作为总和是合适的,我在这里进一步作出有关的步幅可能有些不太准确assumtions接近,但很明显,并为您应该只要顺利eDisplay是更多或更少的常规。



文章来源: Doing some basic calculus using Reactive Banana