Date | Version | Content |
---|---|---|
2019-07-04 | 0.1 | First version |
2019-09-20 | 1.0 | Added support for changing awgn and phase noise scaling at run time. |
2020-09-01 | 1.1 | Rewrite of UART component for improved long-term stability |
2021-01-10 | 1.2 | Update phase noise component scaling factor to support smaller linewidth symbol-duration products. |
Verification and testing of complex digital signal processing (DSP) implementations becomes time consuming as the implementations become more complex, especially for designs where low bit-error rate (BER) data is needed. Such designs can be e.g. forward error correction decoders or detection of cycle slips for carrier phase recovery algorithms. The standard way of testing an algorithm implemented in a hardware description language (HDL) is through MATLAB-HDL co-simulation, where the input data is generated in MATLAB, processed by a simulation of the HDL implementation and imported back into MATLAB for post-processing. For low-BER simulations the runtime of these simulations can, however, easily become prohibitively long.
The Chalmers Optical Fiber Channel Emulator (CHOICE), originally presented in [1], aims to reduce the runtime of low-BER simulations by using an FPGA or ASIC to digitally emulate the fiber impairments, using fixed-point representations for all signals. CHOICE generates a long pseudo-random bitstream, modulates it and adds emulated fiber impairments in actual hardware. This emulation can, in conjunction with running the DSP implementation on the same hardware, reduce the simulation time by multiple orders of magnitude.
Currently, CHOICE consists of a pseudo-random bitstream generation component (rng), a modulation component (modulator), an additive white Gaussian noise generator (awgn), a phase noise generator (phase_noise), a demodulator (demodulator) and an error counter (error_counter). All applicable components can be parallelized and the parallelism, i.e. the number of symbols processed per clock cycle, is set by the PAR generic in each parallelizable component. The size of each component is kept as small as possible to be able to test large DSP systems or to run multiple instances of CHOICE simultaneously. Supplied with the package is also a UART controller (uart) and system examples. The latter can be found in the src/examples folder. For the future, the plan is to develop the emulator further by adding more fiber impairments and further developed analysis tools.
CHOICE is written by Erik Börjeson from the Department of Computer Science and Engineering at Chalmers University of Technology and is released under version 3 of the GNU General Public License (GPLv3). If you use CHOICE in your work, please cite [1].
The git repo can be cloned by doing
git clone http://www.cse.chalmers.se/~erikbor/choice/choice.git.
To also include the Gaussian noise generator (GNG) IP core used, do
git clone --recurse http://www.cse.chalmers.se/~erikbor/choice/choice.git.
More information about the GNG IP core can be found under the description of the AWGN component.
This section describes the components of the CHOICE system and how to use them. An example of how a CHOICE system can be implemented is shown in Fig. 1. The binary data is generated in the rng component and fed to the modulator component. AWGN and phase noise are added and symbols are fed to the dsp unit under test. The output from the tested unit is demodulated and the errors are counted. Each component takes both the modulated signal (i_in and q_in) as well as the transmitted bits (bits_in) as inputs. The bits are delayed to match the symbols so that the output of each block contains both the symbols (i_out and q_out) and the matching transmitted bits (bits_out). Valid signals (valid_in and valid_out) are used to tell the next block in the chain when processing can begin.
An example of how a complete system can be implemented is provided in src/examples/emulator.vhdl with a testbench provided in src/examples/testbench.vhdl. It uses an example DSP component (src/examples/dsp.vhdl), that adds a delay to the symbol stream.
A second example of the same type of system is provided in src/examples/emulator_uart.vhdl, which illustrates the use of the uart component. This component is a UART controller that can be used to transfer data from the FPGA to e.g. a computer for later analysis. The example com component illustrate how the settings can be transmitted to the emulation systems and results from the error_counter block can be sent back. Setting of the SNR and phase noise scaling is done by sending 0x01 0xXXXX 0xYYYY, where XXXX is the SNR scaling and YYYY is the phase noise scaling. Both XXXX and YYYY are 16-bit values that can calculated using the scripts in the scripts folder. The scaling factors used in the emulator are not updated until the simulation is reset by sending 0x00. To read the counter data from the emulator send 0x02. The com component will respond with 16 bytes, where the first 8 represents the bit counter and the last 8 bytes represents the error counter.
Data generation is handled in the rng component using the Xorshift random number generation (RNG) method described by Marsaglia [2]. The rng component works as a wrapper for the xorshift component to generate the needed number of Xorshift RNGs. It also control the generation of the valid_out signal. The periodicity of the pseudo-random bit sequence is 264-1 for an Xorshift register wordlength (N) of 64. The rng component is declared as
Generic | Function |
---|---|
BITS | Number of bits to be generated each clock cycle. |
N | Width of the register in the Xorshift RNGs. |
A, B, C | Shift steps for the Xorshift RNGs, see [2] for suggested values. |
SEED | Seed for the Xorshift RNGs, needs to have a wordlength of N·ceil(BITS/N). |
Filename | Function |
---|---|
src/datagen/rng.vhdl | Main rng component source. |
src/datagen/xorshift.vhdl | Subcomponent used to instantiate the Xorshift RNGs. |
Modulation of the bitstream generated in the rng is handled by the modulator component. Currently, these modulation formats are supported:
Generic | Function |
---|---|
PAR | Parallelization factor of the modulator. |
BITS | Wordlength of the bits_in input. |
MOD_BITS | Number of bits encoded on each symbol. |
MOD_TYPE | Modulation format (BPSK, QPSK, 16QAM, 64QAM, 256QAM) |
WIDTH | Wordlength of the modulated symbols. |
MAX_AMP | Fraction of the i_out and q_out signals to use for the symbol with the largest amplitude (0.0 - 1.0). |
Filename | Function |
---|---|
src/mod/modulator.vhdl | Main modulator component source code. |
src/mod/mod_BPSK.vhdl | Subcomponent for BPSK modulation. |
src/mod/mod_QPSK.vhdl | Subcomponent for QPSK modulation. |
src/mod/mod_16QAM.vhdl | Subcomponent for 16QAM modulation. |
src/mod/mod_64QAM.vhdl | Subcomponent for 64QAM modulation. |
src/mod/mod_256QAM.vhdl | Subcomponent for 256QAM modulation. |
The awgn component adds additive white Gaussian noise to the input I/Q symbols. The noise amplitude is calculated from the generic constants EB and SNR. The component use an Gaussian noise generator IP core, written by Guangxi Liu, based on the principle presented in [3]. The noise generator is available at GitHub under the GNU Lesser General Public License (LGPLv2.1). The periodicity of the GNG is approximately 2175. If you have already cloned the CHOICE repo and want to download the GNG to the appropriate folder in the repo, do git submodule init followed by git submodule update in the CHOICE repo.
Seeds for the two GNG generators needed on each parallel lane for the I and Q signals are taken from the seeds_pkg package, located in the src/support/ folder. Each GNG instance needs three 64-bit vectors as seeds and the awgn and phase noise components are designed to read different seeds from the package. A new seed file can be generated by the scripts/seeds.py script, which takes the number of 64-bit vectors needed as an argument. The 16-bit scaling input signal sets the generated SNR and can be calculated using scripts/snr_scaling.py. A component declaration of the awgn component is shown below.
Generic | Function |
---|---|
PAR | Parallelization factor. |
WIDTH | Wordlength of the I/Q inputs and outputs. |
BITS | Wordlength of the bits_in and bits_out ports. |
Filename | Function |
---|---|
src/channel/awgn.vhdl | Main awgn component source code. |
ip/gng/ | Path to the Gaussian noise generator IP. |
src/support/seeds_pkg.vhdl | Package containing seeds for the GNG. |
CHOICE emulates the phase noise as a Weiner process, using the GNG IP core described above to simulate the random walk. One GNG component is needed for each parallel lane, and the seeds are fetched from the seeds_pkg package. The parallelization of the phase_noise component is currently the limiting factor for the parallelization of the complete system. This limitation is due to the feedback loop present in the implementation, shown in Fig. 2. The 16-bit scaling input signal sets the generated phase noise and can be calculated using scripts/pn_scaling.py. A component declaration template for the phase_noise component is shown below.
Generic | Function |
---|---|
PAR | Parallelization factor. |
WIDTH | Wordlength of the I/Q inputs and outputs. |
BITS | Wordlength of the bits_in and bits_out ports. |
PHASE_WIDTH | Wordlength of the register storing the current phase rotation. |
LUT_WIDTH | Wordlength of the LUT storing rotation vectors. |
Filename | Function |
---|---|
src/channel/awgn.vhdl | Main awgn component source code. |
src/channel/ang_to_iq.vhdl | Component used to convert an angle to an I/Q representation. |
ip/gng/ | Path to the Gaussian Noise Generator IP. |
src/support/seeds_pkg.vhdl | Package containing seeds for the GNG |
Demodulation of the symbols is performed by the demodulator component, supporting the same modulation formats as the modulation component. It instantiates the chosen demodulator and outputs a demodulated bitstream. When using BPSK, the q_in input signal can be connected to a constant. Shown below is an example component declaration of the demodulator.
Generic | Function |
---|---|
PAR | Parallelization factor of the demodulator. |
BITS | Wordlength of the bits_in input. |
MOD_BITS | Number of bits encoded on each symbol. |
MOD_TYPE | Modulation format (BPSK, QPSK, 16QAM, 64QAM, 256QAM) |
WIDTH | Wordlength of the modulated symbols. |
MAX_AMP | Fraction of the i_out and q_out signals to use for the symbol with the largest amplitude (0.0 - 1.0). |
Filename | Function |
---|---|
src/demod/demodulator.vhdl | Main demodulator component source code. |
src/demod/demod_BPSK.vhdl | Subcomponent for BPSK demodulation. |
src/demod/demod_QPSK.vhdl | Subcomponent for QPSK demodulation. |
src/demod/demod_16QAM.vhdl | Subcomponent for 16QAM demodulation. |
src/demod/demod_64QAM.vhdl | Subcomponent for 64QAM demodulation. |
src/demod/demod_256QAM.vhdl | Subcomponent for 256QAM demodulation. |
The output from the demodulator can be connected to the error_counter component. This component counts the number of processed bits and the number of errors detected. The output can be used to analyze the resulting BER. It can be read using a debugger such as Xilinx ChipScope or Intel Quartus SignalTap (pdf). It can also be output from the FPGA using the UART controller provided with CHOICE (src/uart/uart.vhdl), or using other protocols. The component is declared as shown below.
Generic | Function |
---|---|
BITS | Wordlength of the bits_in input. |
BITS_CNT_WIDTH | Wordlength of the bits counter, maximum value of the counter is 2BITS_CNT_WIDTH-1. |
ERROR_CNT_WIDTH | Wordlength of the error counter, maximum value of the counter is 2ERROR_CNT_WIDTH-1. |
Filename | Function |
---|---|
src/analysis/error_counter.vhdl | Main error_counter component source. |
The emulator have been successfully implemented as an 22 nm ASIC design and on the following FPGA development boards: