%% HDL QPSK Transmitter and Receiver
% This example shows how to implement a QPSK transmitter and receiver in
% Simulink(R) that is optimized for HDL code generation and hardware
% implementation.
 
%   Copyright 2020 The MathWorks, Inc.

%%
% The model shown in this example modulates data based on quadrature phase
% shift keying (QPSK). The goal of this example is to model an HDL QPSK
% communication system that can transmit and recover information for a
% real-time system. The receiver implements symbol timing synchronization
% and carrier frequency and phase synchronization, which are essential in a
% single-carrier communication system.

%% System Specifications
% This section explains the specifications of the transmitter and receiver
% used in this example. The frame format is packet based. Each packet has a
% preamble of length 26 bits. Each bit of the 13 bit Barker sequence is
% repeated twice to generate a preamble sequence such that the same bit is
% modulated in the in phase and quadrature phase by the QPSK Modulator. The
% preamble sequence is followed by 2240 bits of payload data. The
% transmitter runs using a root raised cosine (RRC) pulse-shaping filter
% with a roll-off factor of 0.5, resulting in a bandwidth of 1.5 times the
% symbol rate and four samples per symbol (sample rate of four times the
% symbol rate). The RRC impulse response spans over four adjacent symbols.
% The bit rate is twice the symbol rate. The effective average bit rate is
% the bit rate times the frame efficiency. The frame efficiency is
% (2240/(2240+26)) = 0.9885.

%%
% The default symbol rate is set to 1.92 Mbaud, which results in a
% bandwidth of 1.5 times 1.92e6, which equals 2.88 MHz, and a sample rate of
% 4 times 1.92e6, which equals 7.68 Msps, bit rate of 2 times 1.92e6, which
% equals 3.84 Mbps. The effective average bit rate supported by this system
% is 0.9885 times 3.84e6, which equals 3.7959 Mbps. These specifications
% change with a change in the symbol rate.

%% Model Architecture
% This section explains the high-level architecture of the QPSK transmitter
% and receiver as in the block diagram. The QPSK transmitter samples the
% input at a bit rate of twice the symbol rate. The Data Generator &
% Packetizer collects the data bits, generates the preamble bits, and forms
% the packet bits. The HDL Data Scrambler scrambles the data bits of each
% packet to increase bit transitions and avoid long running sequences of
% the same bit. The QPSK Modulator modulates the packet bits to generate
% QPSK symbols. The RRC Transmit Filter upsamples and pulse-shapes the QPSK
% symbols to generate the Tx Waveform at a sample rate of four times that
% of the symbol rate. The QPSK receiver samples the input at the
% transmission rate. The Digital AGC performs gain control to the desired
% amplitude level of the received waveform. The RRC Receive Filter performs
% matched filtering on the AGC output. The Frequency and Time Synchronizer
% performs synchronization operations and generates QPSK symbols for each
% packet. The QPSK Demodulator demodulates the QPSK symbols to generate
% packet bits. The HDL Data Descrambler descrambles the packet data bits
% that stream out of the receiver.

%%
% 
% <<../QPSKBlockDiagram.png>>
% 


%% File Structure
% One Simulink model and three MATLAB(R) files construct this example.

%%
% 
% * |commhdlQPSKTxRx.slx|         &mdash; Top-level Simulink model
% * |commhdlQPSKTxRxParameters.m| &mdash; Generates parameters for QPSK Tx and
% QPSK Rx required for initialization
% * |commhdlQPSKTxRxModelInit.m|  &mdash; Initializes the model
% |commhdlQPSKTxRx.slx|
% * |generateHelloworldMsgBits.m| &mdash; Generates "Hello world _xxx_ "
% message bits. _xxx_ refers to any value from 000 to 100


%% System Interface
% This figure shows the top-level model of the QPSK transmitter and
% receiver system.

%%
Modelname      = 'commhdlQPSKTxRx';
open_system(Modelname);

%%
% *Transmitter Inputs*
% 
% * *dataIn* &mdash;  Input data, specified as a Boolean scalar.
% * *validIn* &mdash; Control signal to validate the *dataIn* , specified as
% a Boolean scalar.

%%
% *Transmitter Outputs*
%
% * *dataOut* &mdash; Output transmitted waveform, returned as 16-bit
% complex data at a sample rate four times that of the symbol rate.
% * *validOut* &mdash; Control signal to validate the *dataOut* , returned
% as a Boolean scalar.
% * *txDiagBus* &mdash; Status signal with diagnostic outputs, returned as
% a Bus signal.
% * *dataReady* &mdash; Signal to indicate a ready for the input signals,
% returned as a Boolean scalar.

%%
% The transmitter enables the *dataReady* signal to indicate that it is
% ready to accept input bits. The transmitter constructs a packet after it
% accepts all the data bits corresponding to that packet. If all the data
% bits corresponding to that packet are not received, the transmitter
% generates dummy packets. For a dummy packet, the Barker sequence is not
% used for the preamble and the data bits are generated randomly
% internally. As long as the input bit rate is less than or equal to the
% effective bit rate, the *dataReady* signal remains high so that the input
% does not get any back pressure from *dataReady*.

%%
% *Receiver Inputs*
% 
% * *dataIn* &mdash;  Input data, specified as a 16-bit complex data with
% sample rate as the transmitter output.
% * *validIn* &mdash; Control signal to validate the *dataIn*, specified as
% a Boolean scalar.

%%
% *Receiver Outputs*
%
% * *dataOut* &mdash; Decoded output data bits, returned as a Boolean
% scalar.
% * *ctrlOut* &mdash; Bus signal with start, end, and valid signals,
% returned as a bus signal.
% * *rxDiagBus* &mdash; Status signal with diagnostic outputs, returned as
% a bus signal.

%% Transmitter Structure
% This figure shows the top-level model of the QPSK Tx subsystem.

open_system([Modelname '/QPSK Tx']);

%%
% *Bit Packetizer*

%%
% The Bit Packetizer subsystem consists of a Packet Controller MATLAB
% function, a Bits Store, and a Multiplexer subsystem. The preamble
% sequence is stored in an look up table (LUT) inside the Preamble Bits
% Store subsystem.  The data bits stream into the Bits Store subsystem and
% are stored in a RAM inside the Data Bits Store subsystem. The Packet
% Controller MATLAB function reads the preamble sequence followed by the
% data bits stored in the RAM for each packet. The Multiplexer subsystem
% streamlines the preamble bits and the data bits.

open_system([Modelname '/QPSK Tx/Bit Packetizer']);

%%
open_system([Modelname '/QPSK Tx/Bit Packetizer/Bits Store']);

%%
% The Data Bits Store subsystem consists of a RAM that can store two
% packets. This RAM provides the flexibility to operate the transmitter
% with a discrete valid input. The Packet Controller MATLAB function reads
% data from the RAM only if the RAM contains a minimum of one packet of the
% data bits. The read and write logic is designed in such a way that the
% RAM does not overflows. When the RAM does not contain a minimum of one
% packet of the data bits, the transmitter generates a dummy packet. The
% Preamble does not use the Barker sequence for a dummy packet so that
% preamble detection does not detect it.

open_system([Modelname '/QPSK Tx/Bit Packetizer/Bits Store/Data Bits Store']);

%%
% *HDL Data Scrambler*

%%
% The HDL Data Scrambler subsystem scrambles the data bits in each packet
% by using the control signals generated by the Bits Generator subsystem.

open_system([Modelname '/QPSK Tx/HDL Data Scrambler']);

%%
% *QPSK Modulator*

%%
% The QPSK Modulator subsystem uses the <docid:comm_ref#fp245939 QPSK
% Modulator Baseband> block to modulate the preamble and data bits to
% generate QPSK symbols. It uses a gray mapping as described in this table.

disp(table(...
categorical({'00'; '01'; '11'; '10'}),...
categorical({num2str(1*exp(1i*pi/4));num2str(1i*exp(1i*pi/4));num2str(-1*exp(1i*pi/4));num2str(-1i*exp(1i*pi/4))}),...
        'VariableNames',...
        {'Bits','Mapping'}));

open_system([Modelname '/QPSK Tx/QPSK Modulator']); 

%%
% *RRC Transmit Filter*

%%
% The RRC Transmit Filter subsystem upsamples the input by a factor of
% four and uses the <docid:dsp_ref#bvi0_ng-1 Discrete FIR Filter HDL
% Optimized> block with an RRC impulse response to pulse-shape the
% transmitter waveform. The receive filter in the QPSK Receiver forms a
% matched filter to this transmit filter.

open_system([Modelname '/QPSK Tx/RRC Transmit Filter']);

%% Receiver Structure
% This figure shows the top-level model of the QPSK Rx subsystem.

open_system([Modelname '/QPSK Rx']);

%%
% *Automatic Gain Control*

%%
% As the input signal amplitude affects the symbol and carrier synchronizer
% PLL performance, the Automatic Gain Control subsystem is placed ahead of
% them. The magnitude squared output is compared with the AGC reference to
% generate an amplitude error. This error is multiplied with the loop gain
% and passed through an integrator to calculate the required gain. The
% resulted gain is multiplied with the AGC input to generate the AGC
% output. For more information, see Chapter 9.5 of [ <#59 1> ].

open_system([Modelname '/QPSK Rx/Automatic Gain Control']);

%%
% *RRC Receive Filter*

%%
% The RRC Receive Filter is a <docid:dsp_ref#bvi0_ng-1 Discrete FIR Filter
% HDL Optimized> block with matched filter coefficients of the filter used
% for pulse-shaping in the transmitter. The RRC matched filtering generates
% an RC pulse-shaped waveform, which has zero ISI characteristics at
% maximum eye opening in the eye diagram of the waveform. Also, the
% matched filtering process maximizes the signal to noise power ratio
% (SNR) of the filter output.

%%
% *Frequency and Time Synchronizer*

%%
% The Frequency and Time Synchronizer subsystem performs symbol
% synchronization, carrier synchronization, and preamble detection for
% packet synchronization. It also estimates and resolves the phase
% ambiguity that is left uncorrected in carrier synchronization.

open_system([Modelname '/QPSK Rx/Frequency and Time Synchronizer']);

%%
% The Symbol Synchronizer subsystem is a PLL-based implementation. It
% generates samples at the optimum time instant (maximum eye opening
% instant) as described in Chapter 8.5 of [ <#59 1> ]. The subsystem
% generates one output sample for every four input samples. The
% Interpolation Filter subsystem implements a piecewise parabolic
% interpolator with a hardware resource efficient farrow structure as
% described in Chapter 8.4.2, and the farrow coefficients are tabulated in
% Table 8.4.1 (the free parameter $\alpha$ of the coefficients is taken as
% 0.5) of [ <#59 1> ]. This filter introduces fractional delays in the input
% waveform. The Gardner TED subsystem implements a Gardner timing error
% detector. The timing error detector is described in Chapter 8.4.1 of
% [ <#59 1> ]. The loop filter filters the timing error and the timing error
% is passed on to the Interpolation Control MATLAB function block. This
% block implements a mod-1 decrementing counter to calculate fractional
% delays based on the loop filtered timing error as described in Chapter
% 8.4.3 of [ <#59 1> ] to generate interpolants at optimum sampling instants.
% The Rate Handle subsystem selects the required interpolant indicated by
% the strobe. This sample corresponds to the maximum eye opening of the eye
% diagram before symbol synchronization.

open_system([Modelname '/QPSK Rx/Frequency and Time Synchronizer/Symbol Synchronizer']);

%%
% The Carrier Synchronizer subsystem is a TYPE II PLL with a sinusoidal
% phase error detector, which operates at a 45 degrees operating point. The
% phase error detector is described in Chapter 7.2.2, and the design
% equations are described in the Appendix C of [ <#59 1> ]. A detailed
% analysis of TYPE II PLL with a zero operating point sinusoidal phase
% detector is described in Chapter 4 of [ <#59 2> ]. The sign function of the
% phase detector in the real and imaginary parts converts all of the angles
% in the 4 quadrants into a first-quadrant angle (0 to 90 degrees), which
% creates an ambiguity of 90,180,270 degrees for second (90 to 180
% degrees), third (-180 to -90 degrees) and fourth (-90 to 0 degrees)
% quadrant angles, respectively. The phase error is calculated as a
% deviation from the operating point (45 degrees) of the phase detector.
% The proportional plus integrator filter in the Loop Filter subsystem
% filters the phase error. The loop filter sets the normalized loop
% bandwidth (normalized by the sample rate) and the loop damping factor.
% The default normalized loop bandwidth is set to 0.005, and the default
% damping factor is set to 0.7071. The filtered error is given as a phase
% increment source to the Direct Digital Synthesis subsystem, which uses
% the <docid:dsp_ref#buh20ru-1 NCO HDL Optimized> block for complex
% exponential phase generation. The complex exponential phase is used to
% correct the frequency and phase of the input. A detailed analysis of
% direct digital synthesis is described in Chapter 9.2.2 of [ <#59 1> ].

open_system([Modelname '/QPSK Rx/Frequency and Time Synchronizer/Carrier Synchronizer']);

%%
% The Preamble Detector subsystem performs continuous correlation for the
% input with the Barker sequence. The correlation is implemented as
% convolution with the reversed Barker sequence as coefficients for the
% <docid:dsp_ref#bvi0_ng-1 Discrete FIR Filter HDL Optimized> block, and
% the magnitude of the correlated output is found using the
% <docid:dsp_ref#bua94sl-1 Complex to Magnitude-Angle HDL Optimized> block
% inside the Correlator subsystem. The magnitude of the correlation is
% compared with a threshold. The Peak Search subsystem begins searching for
% the maximum correlation peak that exceeded the threshold for every one
% frame duration and records the timing offset. The Timing Adjust subsystem
% synchronizes packet timing based on the timing offset to generate
% *syncPulse* signal, which indicates a packet synchronized sample to the
% subsequent subsystem.

open_system([Modelname '/QPSK Rx/Frequency and Time Synchronizer/Preamble Detector']);

%%
% The Phase Ambiguity Estimation and Correction subsystem works based on
% the unique word method for phase ambiguity resolution described in
% Chapter 7.7.1 of [ <#59 1> ]. This method uses the preamble sequence as the
% reference sequence. The reference sequence is conjugated and multiplied
% with the preamble sequence in the input, and the residual phase is
% extracted as the phase ambiguity estimate. This estimate is used to
% correct the ambiguity by rotating the constellation in the opposite
% direction of ambiguity.

open_system([Modelname '/QPSK Rx/Frequency and Time Synchronizer/Phase Ambiguity Estimation and Correction']);

%%
% The Packet Controller subsystem generates control signals for the packet
% boundaries.

%%
% *QPSK Demodulator*

%%
% The QPSK Demodulator subsystem uses the <docid:comm_ref#fp245824 QPSK
% Demodulator Baseband> block to demodulate the packet synchronized symbols
% and generate bits.

%%
open_system([Modelname '/QPSK Rx/QPSK Demodulator']);

%% 
% *HDL Data Descrambler*

%%
% The HDL Data Descrambler subsystem descrambles the demodulated bits to
% generate the user bits.

%%
open_system([Modelname '/QPSK Rx/HDL Data Descrambler']);
%%
close_system(Modelname,0);

%% Run the Model
% The |QPSKTxRxVerification.m| script describes a procedure to initialize,
% generate inputs, run, and verify the |commhdlQPSKTxRx.slx| model by using
% the |commhdlQPSKTxRxModelInit.m| initialization script. You can assign
% custom data to the variables from the Custom Frame Configuration section
% in this script and run the script to run the model. This verification
% script generates a reference waveform within the script, compares the
% reference waveform with the transmitter output, and compares the
% transmitted bits with the decoded user bits.

%% Verification and Results
% Run |QPSKTxRxVerification.m| to run the model.

%%
% >> QPSKTxRxVerification 
load_system(Modelname);
open_system([Modelname '/Control Scope']);
QPSKTxRxVerification;

%%
close_system(Modelname,0);

%% HDL Code Generation
% Pipeline registers (shown in cyan) are added throughout the model
% to make sure the transmitter and receiver subsystems do not have a long
% critical path.

%%
% To check and generate the HDL code referenced in this example, you must
% have the HDL Coder(TM) product.

%%
% To generate the HDL code for transmitter and receiver subsystems, update
% the models and use the following command:

%% 
%    makehdl('commhdlQPSKTxRx/QPSK Tx')  and   makehdl('commhdlQPSKTxRx/QPSK Rx')

%%
% To generate test bench, use the following command:

%%
%    makehdltb('commhdlQPSKTxRx/QPSK Tx')  and   makehdltb('commhdlQPSKTxRx/QPSK Rx')

%%
% Test bench generation time depends on the simulation time.

%%
% The resulting HDL code is synthesized for the Xilinx(R) Zynq(R)-7000
% ZC706 evaluation board. The post place and route resource utilization is
% shown in this table. The maximum frequency of operation is 280 MHz for the 
% transmitter and 215 MHz for the receiver.

%%
F = table(...
    categorical({'Slice Registers'; 'Slice LUT'; 'RAMB36'; 'RAMB18'; ...
    'DSP48'}),...
    categorical({'318'; '137'; '0'; '1'; '18'}),...
    categorical({'6231'; '4506'; '8'; '0'; '88'}),...
    'VariableNames',...
    {'Resources','Tx Usage','Rx Usage'});

disp(F);

%% Further Exploration
% You can modify the channel conditions by tuning the variables listed in this table in the
% |QPSKTxRxVerification.m| script and then running the script. The script applies
% the channel conditions and runs the model.

disp(table(...
    categorical({'dataBits'; 'Rsym'; 'fractionalTimingOffset'; 'timingFrequencyOffset'; 'EbN0dB'; 'CFO'; 'CPO'}),...
    categorical({'Data bits to the transmitter';...
    'Symbol rate specified in symbols per second';...
    'Normalized timing phase offset specified in the range >= 0 and < 1';...
    'Timing frequency offset specified in PPM';...
    'Energy per information bit to single sided noise power spectral density specified in dB';
    'Carrier frequency offset specified in Hz';...
    'Carrier phase offset specified in degrees'}),...
    'VariableNames',...
    {'Variable Name','Description'}));

%% References
% 1. Michael Rice, _Digital Communications - A Discrete-Time
% Approach_, Prentice Hall, April 2008.
%
% 2. Floyd M.Gardner, _Phaselock Techniques_, Third Edition, John Wiley &
% Sons, Inc., 2005
%
