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.