Matthew van Eerde's web log
I am a Software Development Engineer in Test working for the Windows Sound team. You can contact me via email: mateer at microsoft dot com
Friend key: 28904932216450_59cd9d55374be03d8167d37c8ff4196b
Suppose you want to generate a continuous sine-sweep from time tstart to time tend. You want the starting frequency to be ωstart, and the ending frequency to be ωend; you want the sweep to be logarithmic, so that octaves are swept out in equal times. (The alternative would be to sweep linearly, but usually logarithmic sweeping is what you want.) For today we're going to have continuous time and sample values, so sample rate and bit depth will not be part of this discussion; in particular, the units of t will be seconds, and our sample values will go from -1 to 1.
Here's a picture of want we want to end up with:
Without loss of generality, set tstart = 0. This simplifies some of the math.
Let ω(t) be the "instantaneous frequency" at time t. Advanced Exercise: Define "instantaneous frequency" mathematically.
Sweeping ω(t) logarithmically means that log ω(t) is swept linearly from log ωstart to log ωend. So
Quick check: ω(0) = ωstart, ω(tend) = ωend. Yup.
Let's define R (the rate of change of the frequency) as (ωend / ωstart)1 / tend. This formula reduces to
ω(t) = ωstart Rt
Next step is to look at phase. For a sine wave of constant frequency ω, phase progresses linearly with t on the circular interval [0, 2π):
φ = k ω t
for some constant k. If the frequency of a sine wave was 1 cycle per second, the phase would go from 0 to 2π in a single second - this reveals that the correct value of k is 2π:
φ = 2π ω t
What happens with a variable frequency? A little calculus provides the answer. Consider a small change Δt, small enough so that ω(t) is almost constant over the interval:
Δφ ≈ 2π ω(t) Δt
because over that interval the sine sweep function is well approximated by a sine wave of constant frequency ω(t).
Starting from an initial phase φstart, let Δt → 0, and:
u = τ log R
τ = u / log R
dτ = du / log R
B = 2π ωstart / log R
A = φstart - B
and we have:
φ(t) = A + BRt
Just for fun, here's the explicit solution without intermediate values:
Now, the payoff: the signal is just the sine of the phase, so our sine sweep is:
or, more explicitly:
Ah, beautiful mathematically.
But useless practically.
Well, note that our equation for phase is an exponential. That expression inside the sin(...) gets very big, very quickly. Any practical implementation of sin(...) is going to be utterly useless once its argument gets beyond a certain threshold - you'll get ugly chunky steps before you're halfway into the sweep.
Nonetheless, there is a practical way to generate (pretty good) sine sweeps. More on that next time.
EDIT: all logs are base e.
Ramanujan the gifted mathematician once said with pride that he has invented ------ (i don't remember) which will be of no practical use. But alas it did find uses elsewhere!
First, I implemented this and it works just fine for "reasonable" lengths of time. I implemented in C# using (8-byte) doubles. Secondly, I think there's a better (easier to implement, easier to describe, and perhaps more "correct") approach :-)
Generally (regardless of the frequency function), the function s(t) can be expressed as
s(t) = a * sin(2 * pi * i(t));
where t is time, a is amplitude, sin is our favorite sine function, pi is ... pi, i is the integral of the frequency function from 0 to t. So, if
f(t) = s(k^t)
where f is the frequency function, t is time, s is the starting frequency, and k is the konstant ((endfreq - startfreq)/length), i is
i(t) = s( ( k^t-1 )/( ln(k) ) )
(Sorry, I'm not sure how to typeset that better) where ^ is the power function, and ln is the natural log function.
How does this relate to your answer ? I have to go now, but plan on looking at this post more soon.
"gets very big, very quickly." I don't think so. Although some term is brought to the "t" power, that term was already brought to the "1/t_end" power meaning that the resultant power is no bigger than 1.
It looks like we are at the same approach, although you've explored the special case of exponential frequency change.
First 2 members inside sin is const from t - it is initial phase.
The third member is just 2*pi*Wstart * Tend/ln(Wend/Wstart)
The fourth member if (Wend/Start)^(t/Tend) - exponent is always in (0, 1] interval