Implementation
Notes
This page includes some details for software developers who
may wish to extend the capability of Amnici, or change some
of its behavior.
Audio
Amici does not use Core Audio
directly. It uses the Audio Library
framework, and Amici embeds the
framework into the application bundle as
described here.
Input.m is associated with the input sound card, and
TrackingGenerator.m is associated with the output sound
card. All sound card menus and controls are implemented
as Managed Controls of the Audio Library
framework.
Bandwidth
The comments at the beginning
of Spectrum.m contains some details on effective bandwidths
of a Hann window, a Blackman window and a Gaussian window
with various variance (sigma). For example, the effective
bandwidth of the Hann is the well known factor of 1.5. The
factor of the Blackman window is 1.728 and the Gaussian's
bandwidth can be controlled by the Gaussian's standard
deviation.
To get spectrum using the Hann or Blackman windows, the
width of the window is first determined from the required
bandwidth. An FFT size (power of 2) that is larger than the
window width is then chosen, and the window is zero filled
to discard the unwanted samples. As a result, each bin will
have a bandwdith that is greater than a bin
width of the
resultant transform and also as a consequence, the
resultant bins will have overlapping passbands.
Windowing basically trades off the response of far-away
bins (e.g., the sin(f)/f response of an unwindowed FFT) by
widening the response from the adjacent bins. The
"frequency response" of a Hann window, for example, covers
3 bins with a (0.5,1,0.5), i.e., the transfer function
overlaps by a factor of 0.5 into adjacent bins.
In addition to that, Amici further shrinks the window width
to obtain bandwidths that are perfect 5 dB multiples of 1
Hz.
Because a Gaussian has an infinitely long tail and the
values at the ends of a finite window will not be zero, the
Gaussian is multiplied by a Hann and used as the "Gaussian
window"). This avoids the display from "bouncing" from
trace to trace due to boundary value conditions (one of the
reasons why practical Fourier windows have zero at the
ends). As can be seen in the figures in the Resolution
Bandwidth section of the Amici manual, this extra Hann
window does not destroy the primary characteristic of the
Gaussian, not raise the filter sidelobes to any important
degree.
As a result, the computation of the bandwidth of the
Gaussian+Hann combination is rather convoluted [sic]., as
seen in the -generateGaussian:length:fraction:
in Spectrum.m. From
a given variance, the variance (2.25) due to the Hann
window is first subtracted (the standard distribution of
the Hann contributing to its effective bandwidth is 1.5,
and the square of it is subtracted from the desired
bandwidth of the combined Gaussian+Hann).
A
lot of work had gone into this part of Amici's design. But
I wanted a spectrum analyzer that is calibrated for 1 Hz
bandwidth (and 5 dB steps from there:, viz. 3.16 Hz, 10 Hz,
31.6 Hz, 100 Hz), not some arbitarry bandwidth that depends
on the size of the FFT and the sampling rate.
Test
Generator
Amici replaces the input samples (but keeps using the input
device's sampling rate) in -inputReceivedFromSoundcard:buffers:numberOfBuffers:samples:
of input.m if you
define the string TESTSOURCE in input.h.
In addition to a sinusoid, the test generator adds a noise
term from a uniformly distributed random number generator
that is scaled by sqrt(3). (Recall that a uniform
probability density function between (-1,+1) has a variance
of 3). This noise energy is distributed evenly between 0
and N/2 Hertz when the sampling rate is N samples per
second.
Tracking
Generator
Amici generates a new buffer with the sin() function each
time the output sound card requires it. The argument T of
sin() is a second order DDA (digital differential
analyzer). The first order term dT defines the frequency
term and is determined by the instantaneous frequency of
the tracking generator and sampling rate of the output
sound card. The second order term
d2T is the linear sweep term of
the tracking generator.
Both dT and d2T are defined when the tracking
generator is started in the -start:
method.
To avoid any potential rounding errors over a sweep,
AppDelegate.m calls -updateFrequency:
in
TrackingGenerator.m to recompute the value of dT after it
finishes gathering the spectrum from Spectrum.h.