[Haskell-cafe] Phase correction?
mlang at blind.guru
Wed Jun 8 19:17:08 UTC 2022
This is more a math question then a Haskell specific thing.
However, Haskell fits nicely to write down the problem as executable
"pseudo" code, so here I am, knowing that you all can read this and
actually grasp the problem at hand (which I obviously dont).
I stumbled across this while naively playing with C++ infinite ranges,
starting with std::ranges::views::iota. So there I was, happily playing with
signal generation, until I went stuck here: Modulating oscillation
frequency while trying to stay stateless. But code says more then a
foreign language, so:
-- stack --resolver lts-19.8 runghc
n = [0 ..]
d = 10 -- EXAMPLE, usually 48000
t = (% d) <$> n
sine f = (\x -> sin $ 2*pi * fromRational x * f x) <$> t
sine1 = sine $ const 1 -- OK
-- Lets devise a method to specify a value changing over time
data I = No | Lin | Exp
erp No a _ _ = a
erp Lin a b mu = (1 - mu) * a + mu * b
erp Exp a b mu = a * ((b / a) ** mu)
data Curve a = Curve a [(I, Double, a)]
at (Curve p1 ) _ = p1
at (Curve p1 ((i, d, p2):xs)) t = go 0 d p1 p2 i d xs where
go t1 t2 p1 p2 i d xs
| t < t2 = erp i p1 p2 $ (t - t1) / d
| null xs = p1
| (i', d', p2') <- head xs = go t2 (t2 + d') p2 p2' i' d' $ tail xs
-- Frequency modulation?
c = Curve 1 [(Exp, 1.0, 2), (Exp, 1.0, 1)]
sine2 = sine $ at c . fromRational -- WRONG!🙅
-- Whenever a change occurs, phase is incorrect
-- because current step doesn't know about the past
main = do
print $ take 10 $ sine1
print $ at c 0.5 == at c 1.5
print $ take 10 $ sine2
-- The naive question of an experimenting non-math coder person is:
-- Can a version of `at` be written which compensates for the phase
-- differences which runs in O(n) where n is the number of curve points?
-- Intuitively this should be possible given `d` (denominator).
at' :: Curve a -> Ratio b -> a
at' c t = undefined
More information about the Haskell-Cafe