%% HDL OFDM Transmitter
% This example shows an OFDM-based wireless transmitter implemented in
% Simulink(R) that is optimized for HDL code generation and hardware
% implementation.

% Copyright 2020 The MathWorks, Inc.

%%
% This example shows the custom design of an orthogonal frequency-division
% multiplexing (OFDM) based transmitter. This transmitter model accepts
% payload data through the input port. It allows you to choose the
% modulation type and the punctured convolutional code rate of the data
% from a set of values. These two parameters control the effective data
% rate of transmission and they can be provided through the input ports of
% transmitter. The maximum data rate supported by the transmitter is 3
% Mbps. The transmitter also accepts an input packetValid signal to control
% the transmission.
% 
%
% The transmitter in this example works in conjunction with the receiver in
% the <docid:whdl_ug#mw_081fbaf8-7329-465c-b90c-d8456e7c6637 HDL OFDM
% Receiver> example. The transmitter has a MATLAB(R) floating point
% equivalent function described in the
% <docid:whdl_ug#mw_3fac2409-5d22-4fa9-b71f-9e17f4063111 HDL OFDM MATLAB
% References> example.

%% Transmitter Specification
% This section explains the specifications of the transmitter related to
% the OFDM frame configuration and structure, bandwidth, and sample rate.
%
% The transmitter model accepts two parameters, modTypeIndex and
% codeRateIndex, which allow you to specify the modulation type and
% punctured convolutional code rate, respectively, of the data. These two
% parameters are explained in the following tables:
%
% *modTypeIndex*

%%
F1 = table(...
    categorical({'0';'1';'2';'3'}),...
    categorical({'BPSK';'QPSK';'16QAM';'64QAM'}),...
    'VariableNames',...
    {'Value','Represents modulation type'});

disp(F1);

%%
% *codeRateIndex*
%

%%
F2 = table(...
    categorical({'0';'1';'2';'3'}),...
    categorical({'1/2';'2/3';'3/4';'5/6'}),...
    'VariableNames',...
    {'Value','Represents code rate'});

disp(F2);

%%
% *OFDM Frame Structure*
%
% Every OFDM system has a frame structure that shows the distribution of
% samples in the frequency domain across all its subcarriers. The frame
% structure is as shown in the figure. Each OFDM symbol is comprised of 72
% subcarriers, and each OFDM frame consists of 36 OFDM symbols. The frame
% duration is 3 ms. The first OFDM symbol is formed by synchronization
% sequence (SS), second and third symbols are formed by reference signals
% (RS), and the fourth symbol is formed by Header. Data is filled from the
% fifth symbol to the last (36th) symbol. Pilots are inserted between data
% such that there is one pilot for every five data subcarriers as shown
% below. These pilots help detect and correct phase errors at the receiver.
% 
% <<../FrameStructure.png>>
%
% The OFDM parameters used in the model are given below:
%

%%
F = table(...
    categorical({'Sample rate'; 'Subcarrier spacing'; ...
    'FFT Length'; 'Bandwidth of OFDM signal';...
    'Active Subcarriers'; 'Left guard subcarriers'; 'Right guard subcarriers';...
    'Cyclic Prefix length';'Data symbols per frame'; 'Pilots per data symbol'}),...
    categorical({'1.92 Msps'; '15 KHz'; '128'; '1.4 MHz'; '72'; '28';...
    '27'; '32'; '32'; '12'}),...
    'VariableNames',...
    {'Parameter','Value'});

disp(F);



%% Model Architecture
% The following figure shows the high-level architecture of the OFDM
% transmitter. There are five different signals that form the OFDM frame:
% SS, RS, Header, Pilots, and Data. SS, RS, and Pilots are the same for
% every frame. They are stored in seperate look up tables (LUT) and
% accessed whenever required. Header and Data vary based on the inputs
% given to the transmitter. Header bits are formed based on the modulation
% type and code rate input values. These header bits are processed through
% the Header chain as shown in the figure. Payload data is provided as an
% input to the transmitter. This data is processed through multiple stages
% in the Data chain. Individual stages in the Header and Data chains are
% explained in further sections.
% 
% These five signals are multiplexed based on their valid signals and
% stored in a RAM. The RAM holds these signals for a duration of one frame.
% Data stored in the RAM is read out and modulated by the
% <docid:whdl_ref#mw_64bc3c11-7878-4e85-80cd-b4ebfd0dcf3f OFDM Modulator>
% block. The OFDM modulated signal is filtered with a passband frequency of
% 1.4 MHz and sent out as transmitter output.
%
% <<../BlockDiagram.png>>
%

%% File Structure
% This example uses two Simulink models, an initialization script, and a
% MATLAB function:
%
% * |whdlOFDMTransmitter.slx| &mdash; This is the top-level model in this
% example. It has an OFDM Tx subsystem that refers to the |whdlOFDMTx.slx|
% model. There is external interface circuit for the OFDM Tx subsystem,
% which provides inputs and collects outputs from the subsystem. Running
% this model runs the remaining three files.
%
% * |whdlexamples.OFDMTransmitterInit| &mdash; This script initializes the
% |whdlOFDMTransmitter.slx| model. The script is called in the InitFcn
% callback of the model.
%
% * |whdlOFDMTx.slx| &mdash; This model implements the transmitter with
% total configurability. The |whdlOFDMTransmitter.slx| model refers to this
% model as explained above. 
%
% * |whdlexamples.OFDMTxParameters| &mdash; A function that generates
% parameters required for the |whdlOFDMTx.slx| model. This function is
% called in the Model Workspace of the model.
%  


%% Transmitter Interface 
% The top level |whdlOFDMTransmitter.slx| model shows the OFDM Tx subsystem
% and its interface.
%

%%
model_name = 'whdlOFDMTransmitter';
open_system(model_name);

%%
% *Model Inputs*:
%
% * _modTypeIndex_ &mdash; Selects the type of symbol modulation to be
% applied to payload data, specified as a ufix2 scalar. This port accepts
% values |0|, |1|, |2|, and |3| which correspond to modulation types BPSK,
% QPSK, 16QAM, and 64QAM.
%
% * _codeRateIndex_ &mdash; Selects the code rate of punctured
% convolutional code to be applied to payload data, specified as a ufix2
% scalar. This port accepts values |0|, |1|, |2|, and |3| which correspond
% to code rates 1/2, 2/3, 3/4, and 5/6.
%
% * _packetValid_ &mdash; Controls transmission of frames, specified as a
% Boolean scalar. If packetValid is 1, the transmitter outputs a valid OFDM
% frame for given input payload data, modTypeIndex and codeRateIndex
% values. If packetValid is 0, the transmitter outputs a dummy frame
% without the given input configuration and data.
%
% * _dataIn_ &mdash; Input payload data, specified as a Boolean scalar.
%
% All input ports run at a sample rate of 30.72 Msps to support different
% configurations.
%
% *Model Outputs*:
%
% * _txData_ &mdash; Transmitter output, returned as a complex scalar with
% fixdt(1,16,13) datatype sampled at 1.92 Msps.
%
% * _txValid_ &mdash; Control signal that validates _txData_, returned as a
% Boolean scalar sampled at 1.92 Msps.
%
% * _sampleInParam_ &mdash; Control signal used to sample _modTypeIndex_,
% _codeRateIndex_ and _packetValid_ inputs, specified as a Boolean scalar
% sampled at 30.72 Msps.
%
% * _dataReady_ &mdash; Control signal that samples input payload data,
% _dataIn_, specified as a Boolean scalar sampled at 30.72 Msps.
%
% *Sample Input Signals*
%
% The Sample Input Signals subsystem samples _modTypeIndex_,
% _codeRateIndex_ and _packetValid_ signals based on the _sampleInParam_
% signal. This subsystem provides outputs only when there is an active
% _sampleInParam_ signal and retains the previous outputs if the
% _sampleInParam_ signal is inactive. The subsystem stores given input
% modOrder and codeRateIndex values in two LUTs as shown in the figure. If
% _packetValid_ is 1, corresponding modOrder and codeRateIndex values are
% selected from LUTs. The Source Coding function maps modOrder values |2|,
% |4|, |16|, and |64| to the corresponding modTypeIndex values |0|, |1|,
% |2|, and |3| and sets |1| (QPSK) as the default value. It also takes
% codeRateIndex values |0|, |1|, |2|, and |3| from the LUT and sets |0|
% (1/2 code rate) as the default value. If packetValid is 0, the LUTs are
% ignored.
%

%%
open_system([model_name '/Sample Input Signals']);

%%
% *Select Payload Data*
%
% The Select Payload Data subsystem selects input payload data based on the
% _dataReady_ signal. It has a counter that increments when the _dataReady_
% signal turns active. There is an LUT that stores the given input payload
% data. Data from this LUT is selected based on the counter value. There is
% an additional circuit that returns zeros as data after the counter
% reaches maximum count.
%

%%
open_system([model_name '/Select Payload Data']);

%%
close_system(model_name,0);


%% Structure of the Transmitter
% 
% The |whdlOFDMTx.slx| model is called within the OFDM Tx subsystem. It
% generates an OFDM transmitter waveform by processing input signals in
% multiple stages as shown below.
%
% *whdlOFDMTx*
%

%%
modelReference = 'whdlOFDMTx';
open_system(modelReference);

%%
% *Frame Controller and Input Sampler*
%
% The Frame Controller and Input Sampler subsystem has a counter that
% increments for a frame duration of 3 ms and then restarts. The counter
% restarts from |0| at the beginning of every frame and generates the
% _sampleInParam_ signal to sample input signals _modTypeIndex_,
% _codeRateIndex_, and _packetValid_. Based on the sampled _modTypeIndex_
% and _codeRateIndex_ values, corresponding transport block size for the
% frame is selected from the Transport Block Size LUT. Then, the
% _dataReady_ signal becomes active to accept the input data, _dataIn_, of
% size equal to transport block length. If sampled _packetValid_ signal is
% false, _dataReady_ remains inactive indicating generation of a dummy
% frame that does not require any input data. This subsystem also generates
% control signals for SS, RS, Header, Pilot, and Data generation that is
% carried out in further stages.
%

%%
open_system([modelReference '/Frame Controller and Input Sampler']);

%%
% *Frame Generator*
%
% The Frame Generator subsystem consists of five subsystems that generate
% SS, RS, Header, Pilot, and Data signals, which are later OFDM-modulated.
%
% *Frame Generator/SS*
% 
% The SS (Synchronization Sequence) subsystem accepts _ssSet_ control
% signal, generated from the Frame Controller and Input Sampler subsystem.
% It is generated considering the length of SS sequence. This signal
% initially resets the counter. Then, the counter keeps incrementing and
% simultaneously returns SS from an LUT. Once _ssSet_ becomes inactive, the
% counter stops. Output from LUT is upsampled by a factor of 2 to maintain
% the same sample time as that of the Header and Data subsystems. RS and
% Pilot subsystems operate in a similar way by storing the sequences in
% LUTs and accessing them whenever required.
% 

%%
open_system([modelReference '/Frame Generator/SS']);

%%
% *Frame Generator/Header*
%
% The Header subsystem accepts _modTypeIndex_, _codeRateIndex_ and
% _fftLenIndex_ as inputs. A _headerSet_ signal starts the header
% formation. The Header Formation function converts the _modTypeIndex_ and
% _codeRateIndex_ values into their binary equivalents. For example, a
% _modTypeIndex_ value of |1| is converted into two bits |01|. Similarly,
% _codeRateIndex_ values are converted into two equivalent bits. To learn
% more about these indices, refer to *Transmitter Specification*.
% _fftLenIndex_ is not configurable and its value is fixed to |0|. It is
% converted to |000|, which represents an FFT length of 128. _fftLenIndex_,
% _modTypeIndex_, and _codeRateIndex_ are represented using 3, 2, and 2
% bits, forming a total of 7 bits. Additionally, 15 spare bits are added,
% all currently set to |0|, forming a total of 22 Header bits.
%
% These 22 bits are processed as shown below. For proper error detection, 8
% CRC bits are padded using the <docid:comm_ref#btebeql-1 General CRC
% Generator HDL Optimized> block with |[8 7 4 3 1 0]| as the CRC
% polynomial. These 30 bits, that is (22 + 8), are encoded using the
% <docid:whdl_ref#gen_conv_encode Convolutional Encoder> block with |[171
% 133]| as the polynomial and a constraint length of |7|. The encoding is
% done in terminated mode which adds 6 null bits, that is (7 - 1), to the
% CRC padded data. After encoding, these 36 bits result in 72 bits due to
% the 1/2 rate encoding. The output of the <docid:whdl_ref#gen_conv_encode
% Convolutional Encoder> block is a two-element vector that is serialized
% using the <docid:hdlcoder_ref#buhyp0q-933 Serializer1D> block leading to
% rate transition by a factor 2. These 72 bits are BPSK-modulated using the
% <docid:whdl_ref#lte_symbol_mod LTE Symbol Modulator> block to form Header
% symbol.
%

%%
open_system([modelReference '/Frame Generator/Header']);

%%
% *Frame Generator/Data*
%
% The Data subsystem stores input payload data, _dataIn_, and processes it
% through the Data chain.
%

%%
open_system([modelReference '/Frame Generator/Data']);

%%
%
% *Frame Generator/Data/Data and Control Signal Generation*
%
% The Data and Control Signal Generation subsystem consists of a RAM where
% input payload data, _dataIn_, is stored. A _dataSet_ signal reads data
% from this RAM. This subsystem generates _start_, _end_, and _valid_
% control signals for the RAM data. It even selects the puncture vector
% based on the _codeRateIndex_.
%

%%
open_system([modelReference '/Frame Generator/Data/Data and Control Signal Generation']);

%%
% *Frame Generator/Data/Data Chain*
%
% Payload data from RAM and the control signals are given as inputs to the
% <docid:comm_ref#btebeql-1 General CRC Generator HDL Optimized> block,
% which appends a 32-bit CRC to the data with |[32 26 23 22 16 12 11 10 8 7
% 5 4 2 1 0]| as the CRC polynomial. This CRC-padded data is scrambled with
% $x^7+x^4+1$ as the polynomial and |[1 0 1 1 1 0 1]| as the initial state.
% The scrambled data is encoded using the <docid:whdl_ref#gen_conv_encode
% Convolutional Encoder> block in terminated mode using |[171 133]| as the
% polynomial and a constraint length of |7| . This output is punctured using
% the <docid:whdl_ref#puncture Puncturer> block with the puncture vector
% selected in the Data and Control Signal Generation subsystem. The output
% of the <docid:whdl_ref#puncture Puncturer> block is a two-element vector
% and is serialized using <docid:hdlcoder_ref#buhyp0q-933 Serializer1D>
% block. The resultant data is modulated using the
% <docid:whdl_ref#lte_symbol_mod LTE Symbol Modulator> block using the
% modulation pattern selected based on _modTypeIndex_.
% 

%%
open_system([modelReference '/Frame Generator/Data/Data Chain']);

%%
% *Multiplexer*
%
% The Multiplexer subsystem multiplexes the SS, RS, Header, Pilot, and Data
% signals based on the corresponding valid signals that are generated by
% the Frame Generator subsystem.
%

%%
open_system([modelReference '/Multiplexer']);

%%
% *Frame Formation and OFDM Modulation*
%
% The Frame Formation and OFDM Modulation subsystem takes in the
% multiplexed _dataOut_ and _validOut_ signals and writes them into a
% <docid:hdlcoder_ref#buhyp0n-456 Dual Rate Dual Port RAM>. This RAM reads
% and writes data at different rates. Data is written into the RAM at 61.44
% Msps. An LUT contains addresses for writing data into RAM. The RAM is
% filled with data such that it forms an OFDM frame structure as shown in
% the previous sections.
%

%%
open_system([modelReference '/Frame Formation and OFDM Modulation']);

%%
% The OFDM Modulator Valid Generation subsystem generates a valid input
% signal for the <docid:whdl_ref#mw_64bc3c11-7878-4e85-80cd-b4ebfd0dcf3f
% OFDM Modulator> block at a sample rate of 1.92 Msps. This valid signal is
% in synchronization with the ready signal of
% <docid:whdl_ref#mw_64bc3c11-7878-4e85-80cd-b4ebfd0dcf3f OFDM Modulator>.
% The valid signal is also used to generate a RAM address to read data from
% the RAM. The Control Packet Output subsystem selects the
% <docid:whdl_ref#mw_64bc3c11-7878-4e85-80cd-b4ebfd0dcf3f OFDM Modulator>
% output based on _packetValid_. It gives out valid OFDM output in the
% presence of _packetValid_ and a dummy frame with random SS in its
% absence.
%
% *Discrete FIR Filter HDL Optimized*
% 
% The output of the Control Packet Output subsystem is filtered with a
% passband frequency of 1.4 MHz using the <docid:dsp_ref#bvi0_ng-1 Discrete
% FIR Filter HDL Optimized> block . The filter coefficients are computed by
% the |whdlexamples.OFDMTxParameters| function. Output of the filter forms
% the final output of transmitter.
%

%%
close_system(modelReference,0);


%% Run the Transmitter
% The transmitter can be connected back-to-back with the receiver that is
% explained in the <docid:whdl_ug#mw_081fbaf8-7329-465c-b90c-d8456e7c6637
% HDL OFDM Receiver> example. For more information on how to use the
% transmitter and receiver Simulink models back-to-back, refer to the
% <docid:whdl_ug#mw_3fac2409-5d22-4fa9-b71f-9e17f4063111 HDL OFDM MATLAB
% References> example.
%
% To run the transmitter model, |OFDMTxVerification.m| script is provided
% with this example. The script chooses a custom frame configuration, and
% payload data, and simulates the model. The script also collects the
% simulation outputs and validates them.
%

%%
% *NOTE*: These files are not available on the MATLAB search path. To copy
% these files locally to the user path, you must open this example.


%% Verification and Results
% In this section, the OFDM Transmitter Simulink model is validated by
% comparing its output with its floating point equivalent function,
% |whdlexamples.OFDMTx|. For more information on this MATLAB function, see
% the <docid:whdl_ug#mw_3fac2409-5d22-4fa9-b71f-9e17f4063111 HDL OFDM
% MATLAB References> example. To compare the output of the Simulink model
% with the MATLAB function, run the |OFDMTxVerification.m| script. Note
% that for comparison with |whdlexamples.OFDMTx|, _packetValid_ should be
% continuous.
%
% |>> OFDMTxVerification|

%%
OFDMTxVerification

%%
% <<../SpectrumAnalyzer.png>>


%% HDL Code Generation
% To generate HDL code for this example, you must have HDL Coder(TM). Use
% |makehdl| and |makehdltb| commands to generate HDL code and HDL testbench
% for the OFDMTx subsystem. Testbench 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 the table below. Maximum frequency of operation is 227 MHz.

%%
F = table(...
    categorical({'Slice Registers'; 'Slice LUT'; 'RAMB36'; 'RAMB18'; ...
    'DSP48'}),...
    categorical({'5819'; '3631'; '5'; '12'; '24'}),...
    'VariableNames',...
    {'Resources','Usage'});

disp(F);


