%% HDL OFDM Receiver
% This example shows an OFDM-based wireless receiver implemented 
% using Simulink(R) blocks optimized for HDL code generation and hardware 
% implementation.

%   Copyright 2020 The MathWorks, Inc.

%%
% The model shown in this example receives data and decodes it based on the
% orthogonal frequency division multiplexing (OFDM). The main purpose of
% this example is to model a custom HDL OFDM wireless communication
% receiver that can recover information in a real-time scenario and
% supports data rates up to 3 Mbps. This model enables you to configure
% parameters: symbol modulation types such as BSPK, QPSK, 16-QAM, and
% 64-QAM and code rates 1/2, 2/3, 3/4 and 5/6 through punctured convolution
% encoding. This model enables you to control impairments such as carrier
% frequency offset (CFO), carrier phase offset (CPO), and rayleigh fading
% channel, which significantly affect OFDM-based communication system.

%%
% The receiver in this example works in conjunction with the transmitter in
% the *HDL OFDM Transmitter* example. For more information on the
% transmitter and the transmitted frame format, see the
% <docid:whdl_ug#mw_db7bad5f-6c70-4959-bae5-32040f46f063 HDL OFDM
% Transmitter> example. The receiver in this example 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.

%% Model Architecture
% The following figure shows the architecture of an OFDM Receiver. The
% receiver samples the input at 1.92 Msps. These samples stream into the Rx
% Filter. The output from the Rx Filter stream into the Frequency Estimator
% and the Frequency Corrector. The Frequency Estimator and the Frequency
% Corrector estimate and correct CFO respectively and the samples stream
% into the Synchronizing Sequence (SS) Detector. The output of the SS
% Detector is used for the time synchronization. The time synchronized
% samples stream into the OFDM Demodulator, which demodulates the input and
% generates the frequency-domain subcarriers. The Subcarrier Parser parses
% the channel reference subcarriers, header subcarriers, and data
% subcarriers. The channel reference subcarriers stream into the Channel
% Estimator, which estimates the channel frequency response. The Channel
% Equalizer uses these estimates to equalize the header and data
% subcarriers in the frequency domain. The Header Recovery recovers the
% header information using the channel-equalized header subcarriers. The
% CPE Estimator estimates the common phase error (CPE) in the data sub
% carriers that get corrected by CPE Corrector. The Data Recovery uses the
% header information and the CPE-corrected data subcarriers to decode the
% data bits.

%%
%
% <<../OFDMRxblockDiagram.png>>
% 

%% File Structure
% Two Simulink models and three MATLAB files are used to construct
% this example.

%%
% 
% * |whdlOFDMReceiver.slx|            &mdash; Top level OFDM receiver Simulink model
% * |whdlOFDMRx.slx|                  &mdash; Reference model used by the 
% |whdlOFDMReceiver.slx|
% * |whdlexamples.OFDMReceiverInit.m| &mdash; Initialization script for
% |whdlOFDMReceiver.slx| initialized in the model's InitFcn callback.
% * |whdlexamples.OFDMRxParameters.m| &mdash; Initialization function for
% |whdlOFDMRx.slx| initialized in the Model Workspace and model's
% InitFcn callback
% * |whdlexamples.OFDMTx.m|           &mdash; MATLAB floating point equivalent
% transmitter function to generate Tx waveform in 
% |whdlexamples.OFDMReceiverInit.m|

%% Receiver Interface
% This figure shows the top-level model in this example.

%%
modelname      = 'whdlOFDMReceiver';
open_system(modelname);

%%
close_system(modelname,0);

%%
% *Model Inputs*:
% 
% * _dataIn_ &mdash;  Input data, specified as a complex signed 16-bit signal 
% sampled at 1.92 Msps.
% * _validIn_ &mdash; Control signal to validate the _dataIn_, specified as a Boolean scalar.
% * _impairmentControl_ &mdash; Bus signal to control the channel impairments. 

%%
% The _impairmentControl_ bus comprises following signals:

%%
% * _frequencyOffsetCorrectionType_ &mdash; Control signal to indicate whether to |use internally
% estimated frequency offset| or |use externally provided frequency offset| for
% offset correction, specified as Boolean scalar.
% * _externalFrequencyOffset_ &mdash; Real signed 14-bit CFO with 
% range from -7400 Hz to 7400 Hz provided externally for CFO correction.
% * _channelEqualizerControl_ &mdash; Control signal to indicate whether to enable
% or disable channel equalization, specified as a Boolean scalar.
% * _CPECorrectionControl_ &mdash; Control signal to indicate whether to enable or
% disable CPE correction, specified as a Boolean scalar.

%%
% *Model Outputs*:
%
% * _dataOut_ &mdash; Decoded output data bits, returned as a Boolean scalar.
% * _validOut_ &mdash; Control signal to validate the _dataOut_, returned as a Boolean scalar.
% * _diagBus_ &mdash; Status signal with diagnostic outputs, returned as a Bus signal.

%% Structure of the Receiver
% The OFDM Rx subsystem performs a set of operations in a sequence. This
% subsystem uses the |whdlOFDMRx.slx| reference model. This reference model
% is initialized in its Model Workspace and model's InitFcn callback using
% the |whdlexamples.OFDMRxParameters| function. The following figure shows
% the top-level subsystems in the reference model.

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

%%
% *Synchronization and OFDM Demodulation*

%%
% The Synchronization and OFDM Demodulation subsystem performs frequency
% and time synchronizations and OFDM demodulation.

%%
open_system([modelReference '/Synchronization and OFDM Demodulation']);

%%
% The Frequency and Time Synchronization subsystem comprises Timing
% Adjust MATLAB function block and CFO Estimation and Correction and SS
% Detection subsystem.

%%
open_system([modelReference '/Synchronization and OFDM Demodulation/Frequency and Time Synchronization']);

%%
% The CFO Estimation and Correction and SS Detection subsystem comprises
% CFO Estimation and SS Detection subsystem and Frequency Correction Nx
% subsystem, which perform frequency correction for the input signal. The
% estimate from the CFO Estimation and SS Detection subsystem is used for
% frequency correction if the _frequencyOffsetCorrectionType_ signal on the
% top-level model interface is set to |use internally estimated frequency
% offset|. The _externalFrequencyOffset_ is used for frequency correction
% if the _frequencyOffsetCorrectionType_ signal is set to |use externally
% provided frequency offset|.

%%
open_system([modelReference '/Synchronization and OFDM Demodulation/Frequency and Time Synchronization/CFO Estimation and Correction and SS Detection']);

%%
% The CFO Estimation and SS Detection subsystem comprises CFO Estimation
% subsystem, Start Controller MATLAB function block, Sync Signal Search
% subsystem, and Frequency Correction 1x subsystem that performs frequency
% correction on input signal.
%%
open_system([modelReference '/Synchronization and OFDM Demodulation/Frequency and Time Synchronization/CFO Estimation and Correction and SS Detection/CFO Estimation and SS Detection']);

%%
% The CFO Estimation subsystem uses the cyclic prefix correlation technique
% to estimate the CFO of the input signal. The CyclicPrefixCorrelator
% subsystem estimates one CFO value for every six OFDM symbols by averaging
% all the estimates in six OFDM symbols. The AngleAtMaximum subsystem
% selects the strongest correlation peak for every six OFDM symbols and
% records its phase angle. The AngleFilter subsystem implements an
% averaging filter to average all the recorded phase angles for a duration
% of 12 ms. The resulting phase angle serves as a final CFO estimate.

%%
open_system([modelReference '/Synchronization and OFDM Demodulation/Frequency and Time Synchronization/CFO Estimation and Correction and SS Detection/CFO Estimation and SS Detection/CFO Estimation']);

%%
% The Sync Signal Search subsystem implements the SS correlation. SS
% detection is performed by continuously cross-correlating the received
% signal with the SS signal in the time domain. In addition, the energy of
% the signal within the span of the correlator is computed on each time
% step and then scaled to generate a threshold. The Max Peak Searcher
% subsystem begins searching for the maximum correlation peak after 12 ms
% and searches for every 3 ms time window and records the timing offset.
% The Start Controller function block indicates the end of 12 ms duration
% to the Max Peak Searcher subsystem.

%%
open_system([modelReference '/Synchronization and OFDM Demodulation/Frequency and Time Synchronization/CFO Estimation and Correction and SS Detection/CFO Estimation and SS Detection/Sync Signal Search']);

%%
% The timing offset recorded at the maximum correlation value by the Max
% Peak Searcher is transferred to the Timing Adjust MATLAB function block
% to synchronize timing.

%%
% The <docid:whdl_ref#gen_ofdm_demod OFDM Demodulator> block demodulates
% the synchronized samples and generates subcarriers.

%%
% *Channel and CPE Estimation and Correction*

%%
% The Channel and CPE Estimation and Correction subsystem estimates the
% channel frequency response, equalizes the channel, performs CPE
% estimation, and corrects the CPE.

%%
open_system([modelReference '/Channel and CPE Estimation and Correction']);

%%
% The Reference Signal Parsing MATLAB function block separates the 
% OFDM symbols reserved for computing channel estimates.

%%
% The OFDM symbols reserved for computing channel estimates are streamed
% through Channel Estimation subsystem. The
% <docid:whdl_ref#mw_bffca2a0-5fec-4daa-89eb-458deb734e8d OFDM Channel
% Estimator> block averages the estimates from the two symbols and outputs
% the final channel estimates. The estimates are streamed into the Channel
% Equalization subsystem, which stores the estimates in a RAM and performs
% frequency-domain channel equalization for all the remaining OFDM symbols
% in the frame.

%%
open_system([modelReference '/Channel and CPE Estimation and Correction/Channel Estimation and Equalization']);

%%
% The Header and Data Parsing MATLAB function block separates the 
% OFDM symbols corresponding to header and data symbols.

%%
% The frequency domain channel-equalized data subcarriers stream through
% the Common Phase Error Estimation and Correction subsystem. In the
% frequency estimation process, there is always a small estimation error
% due to the channel impairments. This estimation error results in a
% residual frequency offset in the channel-equalized subcarriers. This
% results a CPE in all the subcarriers in an OFDM symbol and changes from
% symbol to symbol. The CPE Estimation subsystem estimates the CPE on each
% OFDM symbol using the 12 pilot subcarriers. The pilots are the known
% subcarriers and any phase rotation in the received symbols is estimated
% by using the pilots. The estimates drawn from the same symbol are
% averaged to get the final estimate. The symbol is stored in the Symbol
% Buffer MATLAB function block during estimation. Once the estimate is
% ready, the symbol is read from this buffer block and the CPE Correction
% subsystem corrects the CPE in the data subcarriers with that estimate.

%%
open_system([modelReference '/Channel and CPE Estimation and Correction/CPE Estimation and Correction']);

%%
% *Header and Data Recovery*

%%
% The Header and Data Recovery subsystem recovers the header information
% and the data bits.

%%
open_system([modelReference '/Header and Data Recovery']);

%%
% The Header Recovery subsystem recovers the header information to decode
% data bits. The frequency domain channel-equalized header subcarriers
% stream into the Header Recovery subsystem. The
% <docid:whdl_ref#lte_symbol_demod LTE Symbol Demodulator> block performs
% BPSK soft symbol demodulation. The Channel Coding subsystem is equipped
% with <docid:whdl_ref#mw_a23db9c1-3650-43c5-bb35-62d4b89917ff Viterbi
% Decoder> block, which performs 1/2 rate viterbi decoding. The
% <docid:comm_ref#btjtaxm General CRC Syndrome Detector HDL Optimized>
% block performs 8-bit CRC checksum and validates the decoded bits from the
% Viterbi Decoder block. The CRC syndrome detector block generates an error
% signal, if the CRC checksum fails.

%%
open_system([modelReference '/Header and Data Recovery/Header Recovery']);

%%
% The Data Recovery subsystem uses the header information to decode the
% data bits. The header information is stored in the registers. These
% registers are used to access the header information. The
% <docid:whdl_ref#lte_symbol_demod LTE Symbol Demodulator> block performs
% soft bit BPSK, QPSK, 16-QAM or 64-QAM symbol demodulation associated with
% the modulation type retrieved from the header information. The Channel
% Coding subsystem is equipped with
% <docid:whdl_ref#mw_c2fdf69f-6237-4864-b906-6889c3770752 Depuncturer> and
% <docid:whdl_ref#mw_a23db9c1-3650-43c5-bb35-62d4b89917ff Viterbi Decoder>
% blocks. Each code rate is assigned a predefined punctured vector pattern.
% Based on the code rate retrieved from the header information, the Channel
% Coding subsystem performs depuncturing followed by viterbi decoding. The
% decoded bits are streamed through the Descrambler subsystem. The
% <docid:comm_ref#btjtaxm General CRC Syndrome Detector HDL Optimized>
% block performs 32-bit CRC checksum and validates the descrambled bits.
% The CRC syndrome detector block generates an error signal, if the CRC
% checksum fails.

%%
open_system([modelReference '/Header and Data Recovery/Data Recovery']);

%%
% *Diagnostic Bus Formation*

%%
% The Diagnostic Bus Formation subsystem creates a bus signal for some
% status signals of the receiver. This bus can be used to analyze the
% receiver when deployed onto the hardware.

%%
% The data bits are decoded in the Data Recovery subsystem and bits stream
% out of the receiver and are stored to workspace in the Capture Data Bits
% subsystem in the top-level receiver model. The Diagnostics Decoder
% subsystem decodes the source-coded header information and counts the
% number of synchronized frames, number of header CRC passes and failures,
% and the number of data CRC passes and failures in the bus signal formed
% in the Diagnostic Bus Formation subsystem. The Simulink display blocks
% display the Diagnostics Decoder information.

%% 
%
% <<../OFDMRxresults.png>>
%

%%
close_system(modelReference,0);

%% Run the Receiver
% Connect the receiver back-to-back with the transmitter in the
% <docid:whdl_ug#mw_db7bad5f-6c70-4959-bae5-32040f46f063 HDL OFDM
% Transmitter> example and run the Simulink model. For more information on
% how to connect the transmitter and the receiver Simulink models
% back-to-back see the
% <docid:whdl_ug#mw_3fac2409-5d22-4fa9-b71f-9e17f4063111 HDL OFDM MATLAB
% References> example.

%%
% The following files describe a procedure to initialize, generate inputs,
% run, and verify the |whdlOFDMReceiver.slx| model using the
% |whdlexamples.OFDMReceiverInit.m| initialization script. You can choose a
% custom Tx waveform and a channel impairment of your choice from the
% Custom Frame Configuration section in these files.

%%
% * |OFDMRxRealTimeSimulationDisplay.m|    - This script mimics a channel
% in a 
% real-time scenario. You can choose any available channel impairment and run the 
% script. The script displays the outputs and generates
% plots of estimated frequency offset and SS correlation.
% * |OFDMRxFadingChannelResponseDisplay.m| - This script mimics only the fading 
% channel. You can choose only the fading channel impairment 
% and run the script. The script displays the outputs and generates the 
% plots of channel impulse response and the comparison of estimated 
% frequency response with the frequency response, derived from the impulse 
% response.

%%
% *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
% The |whdlexamples.OFDMRx.m| script is a MATLAB floating point equivalent
% of the reference model |whdlOFDMRx.slx|. The Simulink model and MATLAB
% floating point equivalent script are compared in the
% <docid:whdl_ug#mw_3fac2409-5d22-4fa9-b71f-9e17f4063111 HDL OFDM MATLAB
% References> example.

%%
% Run the |OFDMRxRealTimeSimulationDisplay.m| script to run the receiver.

%%
%  >> OFDMRxRealTimeSimulationDisplay

%%
OFDMRxRealTimeSimulationDisplay

%%
% Run the |OFDMRxFadingChannelResponseDisplay.m| script to run the receiver.

%%
%  >> OFDMRxFadingChannelResponseDisplay

%%
OFDMRxFadingChannelResponseDisplay

%%
% You can see the constellation plot on the constellation scope. The
% scopes can be activated by using the Control Scope button in the 
% |whdlOFDMReceiver.slx| model.
%
% <<../OFDMRxConstellation.png>>

%% HDL Code Generation
%
% To generate the 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 OFDM Rx subsystem. The testbench generation time
% depends on the simulation time.
%
% The resulting HDL code is synthesized for a Xilinx(R) Zynq(R)-7000 ZC706
% evaluation board. The post place and route resource utilization and are
% shown in the table below. The maximum frequency of operation is 192 MHz.

%%
 F = table(...
    categorical({'Slice Registers'; 'Slice LUT'; 'RAMB36'; 'RAMB18';...
    'DSP48'}),...
    categorical({'45122'; '36246'; '8'; '9'; '95'}),...
    'VariableNames',...
    {'Resources','Usage'});

disp(F);
