151 lines
5.8 KiB
Plaintext
151 lines
5.8 KiB
Plaintext
|
|
Sine / cosine generator in VHDL
|
|
=================================
|
|
|
|
This package contains a sine / cosine generator in synthesizable VHDL code.
|
|
|
|
The core takes a phase value as input and produces the corresponding sine
|
|
and cosine as signed integer outputs. The core is fully pipelined, accepting
|
|
a new phase input on every clock cycle. The corresponding sine/cosine outputs
|
|
appear after a latency of 6 or 9 clock cycles (depending on configuration).
|
|
|
|
The VHDL code has been optimized for Xilinx FPGAs and is arranged
|
|
to make efficient use of block RAM and DSP primivites in Xilinx FPGAs.
|
|
|
|
|
|
Algorithm
|
|
---------
|
|
|
|
The core uses a small lookup table, with interpolation between table entries
|
|
based on the Taylor series.
|
|
|
|
A lookup table contains a limited number (about 1024) points in the
|
|
first quadrant of the sine function. The following steps are performed
|
|
to compute the sine and cosine of an arbitrary point in the first quadrant:
|
|
|
|
1) Lookup the closest phase point in the sine table. This is done
|
|
simultaneously for the sine and cosine, using cos(x) = sin(pi/2-x).
|
|
|
|
sin_base = table[ i ]
|
|
cos_base = table[ M-i ]
|
|
|
|
These two lookups are done simultaneously, using a table stored
|
|
in a ROM block with two read ports.
|
|
|
|
2) Compute the phase mismatch between the table point and actual
|
|
phase input in radians. This requires multiplication by Pi,
|
|
which is implemented through repeated shifting and adding.
|
|
|
|
3) Use the Taylor series to obtain a more accurate approximation
|
|
of the answer. Depending on the required accuracy, either 1st order
|
|
or 2nd order Taylor approximation is used.
|
|
|
|
sin_improved = sin_base + d_phase * cos_base
|
|
cos_improved = cos_base - d_phase * sin_base
|
|
|
|
or
|
|
|
|
sin_improved = sin_base + d_phase * ( cos_base - d_phase * sin_base / 2)
|
|
cos_improved = cos_base - d_phase * ( sin_base + d_phase * cos_base / 2)
|
|
|
|
This requres two (1st order) or four (2nd order) multiply-accumulate
|
|
steps, which are implemented in DSPs.
|
|
|
|
4) Round the improved result to the required accuracy.
|
|
|
|
Phase points not in the first quadrant are obtained by simple mirroring,
|
|
i.e. swapping of sine and cosine and/or sign flipping based on
|
|
|
|
sin(x+pi/2) = cos(x), cos(x+pi/2) = -sin(x)
|
|
sin(x+pi) = -sin(x), cos(x+pi) = -cos(x)
|
|
|
|
This automatically ensures that the full sine waveform is perfectly
|
|
balanced around zero and that the 90 degree phase shift between sine
|
|
and cosine holds exactly.
|
|
|
|
|
|
Code organization
|
|
-----------------
|
|
|
|
The generic core implementation is only one VHDL file (sincos_gen.vhdl).
|
|
It has tunable parameters to set input/output word length and to trade
|
|
accuracy vs resources. Do not mess around with those parameters!
|
|
Detailed understanding of the algorithm is required to choose good parameters.
|
|
Incorrect parameters may make the output inaccurate or plain wrong.
|
|
|
|
Two wrappers are available which set the parameters for a sensible
|
|
balance between accuracy and efficiency:
|
|
|
|
sincos_gen_d18_p20.vhdl is for 18-bit sine/cosine output.
|
|
sincos_gen_d24_p26.vhdl is for 24-bit sine/cosine output.
|
|
|
|
These two wrappers are the only tested variants of the core.
|
|
|
|
|
|
rtl/ Synthesizable VHDL code
|
|
rtl/sincos_gen.vhdl Implementation of core with tunable generics
|
|
rtl/sincos_gen_d18_p20.vhdl Wrapper for 18-bit output, 20-bit phase variant
|
|
rtl/sincos_gen_d24_p26.vhdl Wrapper for 24-bit output, 26-bit phase variant
|
|
rtl/test_sincos_serial.vhdl Synthesizable test fixture for testing in FPGA
|
|
|
|
sim/ Test benches
|
|
sim/Makefile Makefile for building test benches with GHDL
|
|
sim/sim_sincos_*_probe.vhdl Simulate core for a few phase inputs
|
|
sim/sim_sincos_*_full.vhdl Simulate core for all possible phase inputs
|
|
|
|
tools/eval_sine_quality.py Python program to determine accuracy of
|
|
output from sim_sincos_dXX_pYY_full.
|
|
|
|
synth/ Synthesis runs for Xilinx FPGAs.
|
|
|
|
|
|
Output accuracy
|
|
---------------
|
|
|
|
Accuracy of the sine/cosine output from the cores has been determined from
|
|
a simulation of the VHDL code on all possible phase input values.
|
|
|
|
|
|
----
|
|
Core variant: sincos_gen_d18_p20 sincos_gen_d24_p26
|
|
Phase input width: 20 bits 26 bits
|
|
Sin/cos output width: 18 bits 24 bits
|
|
|
|
Amplitude: 131071.008128 lsb 8388606.997508 lsb
|
|
Offset: 0.000000 lsb 0.000000 lsb
|
|
Phase mismatch: 1.30e-7 rad 1.94e-9 rad
|
|
|
|
Peak absolute error: 0.864721 lsb 0.917662 lsb
|
|
Root-mean-square error: 0.325144 lsb rms 0.326538 lsb rms
|
|
SINAD: 109.09 dB 145.18 dB
|
|
Effective nr of bits: 17.83 bits 23.82 bits
|
|
Spurious-free dynamic range: 135.19 dB 171.50 dB
|
|
|
|
cos(x) == sin(x+pi/2) : exact match exact match
|
|
sin(x) == - sin(x+pi) : exact match exact match
|
|
----
|
|
|
|
|
|
FPGA resources
|
|
--------------
|
|
|
|
----
|
|
FPGA type: Xilinx Spartan-6 LX45-3 Xilinx Virtex-7 485T-1
|
|
Synthesizer: Xilinx ISE 14.7 Xilinx Vivado 2014.4.1
|
|
|
|
Core variant: d18_p20 d24_p26 d18_p20 d24_p26
|
|
|
|
Flip-flops: 136 253 153 295
|
|
LUTs: 124 213 114 182
|
|
RAMB18: 0 0 1 0
|
|
RAMB36: 0 0 0 1
|
|
DSP48E1: 0 0 2 4
|
|
RAMB16BWER: 1 1
|
|
RAMB8BWER: 0 1
|
|
DSP48A1: 2 4
|
|
|
|
Clock freq: 230 MHz 230 MHz 400 MHz 400 MHz
|
|
----
|
|
|
|
|