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:
Substitute: u = τ log R τ = u / log R dτ = du / log R
Define: 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.
Why useless?
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.
Three quarters are better than a dollar because they make noise! -- Lilly, Lilly's Purple Plastic Purse
Last time I talked about how to calculate a sine sweep mathematically. There's a closed-form solution which is quite elegant but, alas, useless in a practical computer implementation due to the very big numbers that are being fed to the sin(...) function.
A computer implementation will care only about the discrete samples that need to be generated. The integral in the previous post turns out to be counterproductive - we're much more interested in the infinite sequence of φi, and more particularly in their residue mod 2π.
Here are Matlab scripts that implement a sine sweep both ways:
First, the naïve mathematical solution that just calculates the exponential:
function signal = sinesweep_nostate( ... start, ... finish, ... seconds, ... sample_rate, ... amplitude, ... initial_phase, ... dc ...)% sinesweep_nostate returns a single-channel sine logarithmic sweep% DO NOT USE THIS FUNCTION IN PRODUCTION% THIS IS A PEDAGOGICAL EXERCISE ONLY% THE SIGNAL THIS PRODUCES GRADUALLY DISTORTS% INSTEAD USE sinesweep% % start: starting frequency in Hz% finish: ending frequency in Hz% seconds: duration of sweep in seconds% samplerate: samples per second% amplitude: amplitude% initial_phase: starting phase% dc: dc% echo these interesting intermediate values to the consoleR = (finish / start) ^ (1 / seconds)B = 2 * pi * start / log(R)A = initial_phase - Btime = 0 : 1 / sample_rate : seconds;phase = A + B * R .^ time;signal = amplitude * sin(phase) + dc;end % sinesweep_nostate
Now, the iterative version that adds up the little Δφs to calculate φi iteratively:
function signal = sinesweep( ... start, ... finish, ... seconds, ... sample_rate, ... amplitude, ... initial_phase, ... dc ...)% sinesweep returns a single-channel sine logarithmic sweep% start: starting frequency in Hz% finish: ending frequency in Hz% seconds: duration of sweep in seconds% samplerate: samples per second% amplitude: amplitude% initial_phase: starting phase% dc: dctime = 0 : 1 / sample_rate : seconds;frequency = exp( ... log(start) * (1 - time / seconds) + ... log(finish) * (time / seconds) ...);phase = 0 * time;phase(1) = initial_phase;for i = 2:length(phase) phase(i) = ... mod(phase(i - 1) + 2 * pi * frequency(i) / sample_rate, 2 * pi);endsignal = amplitude * sin(phase) + dc;end % sinesweep
If anything, one would expect the first to be more accurate, since it is mathematically precise, and the second is only an approximation. But let's see how the signal produced by each of them holds up.
I calculate, and plot, the same sweep both ways, with a slight dc offset to facilitate seeing the different sweeps on the same plot. In particular this is a logarithmic sweep from 20 kHz to 21 kHz, over 30 seconds, using 44100 samples per second, an amplitude of 0.2, an initial phase of π, and a dc of 0.25 for one and 0.26 for the other:
plot(... x, sinesweep(20000, 21000, 30, 44100, 0.2, pi, 0.25), 'd', ... x, sinesweep_nostate(20000, 21000, 30, 44100, 0.2, pi, 0.26), 's' ...)
(x is just 1:30*44100 - necessary to allow a single plot statement.)
Note that the approximate method is plotted in diamonds, and will be 0.01 lower on the resulting graph than the "exact" method, plotted in squares.
(This takes a while to plot because there are a heckuva lot of points...)
Ah, a nice solid mass of green and blue. I won't show it here.
OK, let's zoom in to a very early chunk of the signal - I expect these to match up closely, with only the dc offset separating the points:
Yup. Looks pretty good - give or take a pixel (quantization error in the display.)
Now let's see what happens to the signal towards the end of the 30 seconds.
Ick. Something's rotten in the state of Denmark. This distortion is so bad that it's visible - you don't even have to take an FFT to see it.
Exercise: take an FFT and look at the distortion.
Advanced Exercise: demonstrate that the distortion is, in fact, in the "exact" method and not in the iterative method... that is to say, show which clock is right.
EDIT: On second glance it looks like the second picture is just showing a horizontal shift between the two signals, which is expected. I'll need to dig deeper if I'm to prove my assertion that the iterative method produces less distortion than the "exact" method.
As preparation for moving one of my machines from Vista to Windows 7, I'm compiling a list of all the little tweaks I like to make to machines that I use a lot:
Boot from the Windows DVD. Delete all partitions; make each hard drive one big partition. (Hmm... apparently Windows 7 really wants a second 100 MB partition. Do the partition dance to force it into installing on a single partition.)
In the "password hint" box, type a misleading hint.
In "Help protect your computer and improve Windows automatically", choose "Ask me later."
Once I'm in, create a new limited user (not a member of the Administrators group) and use that as my primary account.
Control Panel | Hardware and Sound | Mouse Pointers | Enable pointer shadow (uncheck) Pointer Options Enhance pointer precision (uncheck) Hide pointer while typing (uncheck)
Right-click taskbar | Properties | Taskbar Use small icons (check) Taskbar location on screen (change to "Right") Taskbar buttons (change to "Never combine") Notification area | Customize Turn system icons on or off Clock | Off (select) Volume | Off (select) Network | Off (select) ... turn everything off, except sometimes. (for example, I might leave Power on for a laptop.) Always show all icons and notifications on the taskbar (check) Use Aero Peek to preview the desktop (uncheck)
Windows Explorer | Organize Layout | Details pane (uncheck) Folder and search options | View | Advanced settings Always show icons, never thumbnails (check) Always show menus (check) Display file icon on thumbnails (uncheck) Display file size information in folder tips (uncheck) Display the full path in the title bar (Classic theme only) (check) Hidden files and folders | Show hidden files, folders, and drives (select) Hide empty drives in the Computer folder (uncheck) Hide extensions for known file types (uncheck) Hide protected operating system files (Recommended) (uncheck, Yes I'm sure) Show pop-up description for folder and desktop items (uncheck)
Control Panel | System and Security | Windows Update | Change settings Download updates but let me choose whether to install them (select) Allow all users to install updates on this computer (check)
Elevated command prompt | gpedit.msc | Local Computer Policy User Configuration | Administrative Templates | Windows Components Windows Explorer | Turn off numerical sorting in Windows Explorer (enable) Computer Configuration | Administrative Templates System Power Management | Video and Display Settings Turn Off Adaptive Display Timeout (Plugged In) (enable) Turn Off Adaptive Display Timeout (On Battery) (enable) Windows Components | Windows Update Do not display 'Install Updates and Shut Down' ... (enable) Do not adjust default option to 'Install Updates and Shut Down' ... (enable)
Control Panel | View by: Small icons (select) AutoPlay | Use AutoPlay for all media and devices (uncheck) Indexing Options | Modify | Show all locations Offline Files (uncheck) C:\Users (uncheck) C:\ProgramData\Microsoft\Windows\Start Menu (uncheck) Troubleshooting | Change settings | Computer Maintenance | Off (select) Windows Defender | Tools Automatic scanning | Automatically scan my computer (uncheck) Real-time protection | Use real-time protection (recommended) (uncheck) Administrator | Use this program (uncheck)
Right-click Start Menu | Properties Customize Computer | Don't display this item (select) Connect To (uncheck) Control Panel | Don't display this item (select) Default Programs (uncheck) Devices and Printers (uncheck) Documents | Don't display this item (select) Enable context menus and dragging and dropping (uncheck) Games | Don't display this item (select) Help (uncheck) Highlight newly installed programs (uncheck) Music | Don't display this item (select) Open submenus when I pause on them with the mouse pointer (uncheck) Personal folder | Don't display this item (select) Pictures | Don't display this item (select) Search other files and libraries | Don't search (select) Search programs and Control Panel (uncheck) Use large icons (uncheck) Number of recent programs to display (set to 20 to make the menu bigger) Number of recent items to display in Jump Lists (set to 20 to make the menu bigger) Store and display recently opened programs in the Start menu (uncheck) Store and display recently opened items in the Start menu and the taskbar (uncheck)
Right-click everything that is pinned to the taskbar Unpin this program from taskbar
Right-click Recycle Bin | Properties For each hard drive in turn (select) Don't move files to the Recycle Bin. Remove files immediately... (select)
Control Panel | Appearance and Personalization Personalization | Change desktop icons | Recycle Bin (uncheck) Change desktop background Picture Location: Solid Colors (select, choose black)
Control Panel | User Accounts | Change your account picture Browse for more pictures
Control Panel | Ease of access Change how your mouse works Mouse pointers | Regular Black (select) Prevent windows from being automatically arranged when moved to the edge of the screen (check) Change how your keyboard works Set up Sticky Keys | Turn on Sticky Keys when SHIFT is pressed five times (uncheck) Optimize visual display Turn off all unnecessary animations (when possible) (check)
Make a folder on the desktop named "_" Open the following folders simultaneously _ C:\ProgramData\Microsoft\Windows\Start Menu C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu Copy various shortcuts from Start Menu over to _ Notepad Paint Command Prompt Calculator ... whatever else strikes my fancy ... as I install programs, consider adding them here if I use them a lot
Right-click the taskbar | Toolbars | New toolbar... | Desktop | _ (Select Folder) Right-click the taskbar | Lock the taskbar (uncheck) Drag the thumb of the _ toolbar to the top of the taskbar Right-click _ Show Text (uncheck) Show title (uncheck) View | Small Icons (check) Drag the taskbar to be a tiny bit wider so three small icons fit side-by-side Drag the view-active-tasks part of the taskbar to be big Right-click the taskbar | Lock the taskbar (check)
Make a 1-pixel-by-1-pixel black .jpg and set it as the LogonUI background
I'm sure I'm forgetting some other things. I'll add them later when I run into them.
I could probably make a series out of this. Possible candidates for future posts: "Tweaks I make every time I install Office", "Tweaks I make every time I install Firefox"...
Command Prompt | Alt-Space | Defaults | QuickEdit Mode (check)
If you're installing Windows via a boot DVD, and you choose Custom, you have the option to rearrange partitions. I like use this to have each drive be one big partition.
Windows 7 wants to set aside a 100 MB partition for something-or-other. I'm sure there's a very good reason for this but I am too lazy to look up the team that owns this space and ask them what it is.
So I'm in the "Where do you want to install Windows?" stage, I've gone into "advanced drive setup", and I've deleted all the partitions. Fine. I then create a partition that fills the drive, and I get this popup:
Install WindowsTo ensure that all Windows features work correctly, Windows might create additional partitions for system files.OK | Cancel
After letting Windows finish installing, I jump into diskpart.exe and sure enough, Windows has created an additional partition. A small one, to be sure... but an additional partition (horrors!)
Not being one to let Windows push me around, I decided to experiment, and came up with the following dance to allow me to just have one big partition thankyouverymuch:
Bad Perl solution to the "print the open lockers" problem:
perl -e"print join', ',map{$_*$_}1..sqrt pop" 100
54 characters. I prefer this to the 53-character solution obtained by omitting the space after the first comma.
EDIT: 49 characters:
perl -e"print map{$_*$_,' '}1..sqrt pop" 100
EDIT: 48:
perl -e"print map{$_*$_.$/}1..sqrt pop" 100
EDIT: 47:
perl -e"map{print$/.$_*$_}1..sqrt pop" 100
I still think "say" is cheating but it does afford this very short solution:
perl -E"map{say$_*$_}1..sqrt pop" 100
EDIT: Apparently I need to learn how to count. Counts above are off. Anyway, 41:
perl -e"print$_*$_,$/for 1..sqrt pop" 100