Sinusoidal Generation
by Prof. Brian L. Evans
We seek to generate a one-sided discrete-time cosine (or sine) signal
with fixed-frequency w0 of the form
cos(w0 n) u[n]
The sinusoidal frequency, w0, is in
units of radians per sample.
Consider a one-sided continuous-time analog-amplitude cosine of frequency
f0 in Hz
cos(2 pi f0 t) u(t)
sampled at a sampling rate of fs in Hz
by substituting t = n / fs,
cos(2 pi (f0 / fs) n)
u[n]
Hence, w0 =
2 pi f0 / fs.
For example, for f0 = 1200 Hz and
fs = 8000 Hz,
w0 = (3/10) pi.
There are three common methods in software to generate a
one-sided discrete-time sinusoidal waveform on chip:
- Math library function call (e.g. in C)
- Difference equation
- Lookup table
After discussing each method, we compare their design tradeoffs.
1.0 Math Library Function Call
The function call in C would be to the cos
or
sin
function (which requires math.h
).
The calculation is performed in double-precision floating-point
arithmetic.
There is no standard on how the cos and sin C math library functions
are actually implemented.
On a desktop computer, precision of the calculation is
often the primary concern.
Hence, additional computation is used to obtain higher accuracy in
numerical calculations.
In an embedded scenario, implementation complexity is generally
at a premium, so alternate methods are typically employed to compute
cosine and sine values other than a call to a C math library function.
In a desktop scenario, the C function for cos(theta)
could be implemented by the following steps:
- Compute x = theta modulo 2 pi
- Compute a ratio of two 10th-order polynomials in x that
approximate the cosine function
Each 10th-order polynomial can be factored into Horner's form
to minimize the number of multiplications:
a10 x10 +
a9 x9 +
a8 x8 +
... +
a0 =
( ... (((a10 x +
a9) x +
a8) x ... )
+
a0
For each cosine (or sine) value computed, the function call
would need to compute 20 multiplications, 20 additions, and
1 division.
In addition, 22 coefficients would need to be stored in memory.
One intermediate variable, x, would need to be computed.
Calculations are in floating-point arithmetic only.
Version 1.8 of the freely distributable
GNU Scientific Library (GSL)
implements the cosine as the function gsl_sf_cos_e
, where sf means
special function, in the file specfunc/trig.c
.
The implementation uses a Chebyshev approximation over one-eighth
of the period for cosine and sine:
- Compute x = theta modulo (pi/4) and the octant (0-7)
of theta
- Compute an 11th-order polynomial in x that
approximates the cosine function over one octant
For each cosine (or sine) value computed, the gsl_sf_cos_e
function call would need to compute about 20 multiplications,
30 additions, 2 divisions, and 2 power calculations to compute
the cosine value.
Additional computations would be needed to calculate the error
in the approximation.
2.0 Difference Equation
The generation of a one-sided cosine signal
cos(w0 n) u[n]
by using a second-order difference equation is derived on page K-29
in the course reader.
This is problem 1.1 from Midterm #1 from Spring 2004.
The difference equation, with x[n] as input and
y[n] as output, follows:
y[n] =
(2 cos w0) y[n-1] -
y[n-2] +
x[n] -
(cos w0) x[n-1]
The impulse response of the above system, i.e. the response to
x[n] = d[n] where d[n] is
the discrete-time impulse function, will be a one-sided cosine function.
For each cosine (or sine) value computed, the difference
equation would need to compute 2 multiplications and 3 additions.
In addition, 2 coefficients would need to be stored in memory.
Two previous values of y[n] and one previous value of x[n]
would be stored in memory.
Calculations could be performed in floating-point or
fixed-point arithmetic.
2.1 Improving Signal Quality
If the difference equation could be implemented with exact precision
coefficients and arithmetic, then the output cosine signal would have
perfect quality.
However, the representation of values of cos(w0),
with the exception of values -1, -1/2, 0, 1/2, and 1, in floating-point
or fixed-point data types results in a loss of precision of the
coefficients cos(w0) and 2 cos(w0).
In addition, there is potential loss of precision in the
multiplication-accumulation operations.
Loss of precision in coefficient representation and arithmetic operations
will accumulate due to the feedback in the difference equation.
One way to reduce the accumulation of precision loss in cosine sample
calculations is to reboot the filter after each period
of samples has been calculated.
Reboot means to reset the filter to its initial state and run the filter
again.
2.2 First-Order Difference Equation
A first-order difference equation could be used to generate
a sinusoidal signal.
In class today, a student asked whether or not a first-order
difference equation could generate a sinusoidal signal. A
first-order difference equation
y[n] - a y[n-1] = x[n]
with x[n] = d[n] generates one-sided output signals of the form
y[n] = C an u[n]
There are two interesting cases with respect to sinusoidal generation:
- Complex-valued sinusoid of fixed frequency w0 occurs
when a = exp(j w0).
y[n] = C exp(j w0 n) u[n].
- Real-valued sinusoid of fixed frequency w0 = pi occurs
when a = exp(j pi) = -1.
y[n] = C (-1)n = C cos(pi n) u[n].
This is a special case of #1.
3.0 Lookup Table
For the lookup table, we will precompute and store one period of
samples for a cosine.
The cosine frequency w0 can be written as
2 pi N / L.
Here, N and L are integers.
We remove all common factors between N and L.
The value of L is the period of the cosine.
A lookup table of one period would contain L entries.
The entries could be in either floating-point or fixed-point format.
Using symmetry of the cosine over one period, one could store
one-half of the period, or even one-fourth of the period,
provided that L is divisible by 2 or 4, respectively.
Some programmable digital signal processors have read-only memory (ROM)
lookup tables of cos(theta)
and sin(theta)
available on chip.
One can interpolate values in these lookup tables to generate
cosine and sine signals of different frequencies.
4.0 Design Tradeoffs
The tradeoff in signal quality vs. implementation complexity
is described in the table below.
Method
| MACs per cosine sample
| Read-only memory (words)
| Writable memory (words)
| Cosine quality in floating-point
| Cosine quality in fixed-point
|
C function call
| 22
| 22
| 1
| Second best
| Not applicable
|
Difference equation
| 2
| 2
| 3
| Worst
| Second best
|
Lookup table
| 0
| L
| 0
| Best
| Best
|
MACs means multiplication-accumulation operations.
L is the period of the cosine signal.
Additional memory can be saved in the lookup table method by
storing one-half or even one-fourth of the period by using
symmetry properties of the cosine signal, but at a small
increase in computation.
Last updated 06/07/22.
Send comments to
bevans@ece.utexas.edu