
Hi. 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: #!/usr/bin/env stack -- stack --resolver lts-19.8 runghc import Data.Ratio 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 -- CYa, ⡍⠁⠗⠊⠕

On Wed, 8 Jun 2022, Mario Lang wrote:
-- 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
Information that is lost, is lost. You could add the cosine as imaginary part to the sine, in order to form a complex number that stores the phase in its argument (Complex.phase). But I would not do that. It only works for a plain sine wave. For other waveforms like saw tooth, square, etc. you need to maintain the phase (which is the integral of the modulation curve). That's the safe way to go.

Henning Thielemann
On Wed, 8 Jun 2022, Mario Lang wrote:
-- 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
Information that is lost, is lost.
But is it really "lost", given that a Curve knows about all the phase changes in the past? I guess the simplest case would be No interpolation. Thats a single phase change. My math is too bad, but I guess given the denominator (sample rate) and the from and to value of the change, the phase difference should be somehow computable? If so, the next question would be if the linear interpolation case could also be compensated for? Ideally, every interpolation formula would have a phase compensation function. If that is so, how computationally intensive would they be? -- CYa, ⡍⠁⠗⠊⠕
participants (2)
-
Henning Thielemann
-
Mario Lang