You are on page 1of 8

Prototyping as C/C++ Code

457

Understanding LTE with MATLAB457

na

Figure 10.30

Figure 10.31

Options for unbounded variable-sized code generation

Calling the unbounded variable-sized MEX function of a modulator

Prototyping as C/C++ Code


458

10.12

Understanding LTE with MATLAB458

Integration with Existing C/C++ Code

In this section we show how to integrate the generated C/C++ code from a MATLAB
function with an existing C/C++ code or a C/C++ development environment. To do this we
perform the following steps:
1. Choose an algorithm and represent it as a MATLAB
function.
2. Create a MATLAB testbench. A testbench is a calling script that executes the function
with different parameters, records the output of each test case, and records how much
time it takes to complete these test cases. Execute the testbench to generate reference
numerical results and reference execution times.
3. Generate C code from the function. Choose static C library as the code-generation output
type. All the source and header files (*.c and *.h) will be generated in a directory.
4. Compose a C/C++ main function that calls the generated C code.
5. Use a simple Makefile to compile and link the C main function and the generated C code
of the function. The result will be an executable that can run on a computer. This
executable is the C testbench.
6. Run the generated executable (the C testbench) outside the MATLAB environment. Verify that the C testbench generates the same numerical results as the reference MATLAB
testbench. Finally, compare the execution time of the C testbench to a MATLAB
testbench processing the same test cases.

10.12.1

Algorithm

To start the process of integrating MATLAB code with an external C code, we first need to
choose an algorithm. We have selected a simplified form of the Physical Downlink Control
Channel (PDCCH) processing algorithm [3]. In Chapter 9 we examined 17 different
versions of the PDCCH algorithm. In this section we have chosen version 9, the MEX
function of the eighth version of the algorithm, which incorporates all available System
objects in the Communications System Toolbox. Version 9 has been shown to simulate
faster than the first eight versions in the absence of parallel multicore processing. The
MATLAB function that captures the eighth version of the algorithm is as follows:

Algorithm
MATLAB function
function [ber, bits]=zPDCCH_v8(EbNo, maxNumErrs, maxNumBits)
%% Constants
FRM=2048;
M=4; k=log2(M); codeRate=1/3;
snr = EbNo + 10*log10(k) + 10*log10(codeRate);
trellis=poly2trellis(7, [133 171 165]);
L=FRM+24;C=6; Index=[L+1:(3*L/2) (L/2+1):L];
%% Initializations

Prototyping as C/C++ Code


459

Understanding LTE with MATLAB459

persistent Modulator AWGN DeModulator BitError ConvEncoder1 ConvEncoder2 Viterbi


CRCGen CRCDet
if isempty(Modulator)
Modulator
= comm.QPSKModulator('BitInput',true);
AWGN
= comm.AWGNChannel('NoiseMethod', 'Variance', 'VarianceSource',
'Input port');
DeModulator = comm.QPSKDemodulator('BitOutput',true); BitError
= comm.ErrorRate;
ConvEncoder1=comm.ConvolutionalEncoder('TrellisStructure', trellis,
'FinalStateOutputPort', true, ...
'TerminationMethod','Truncated');
ConvEncoder2 = comm.ConvolutionalEncoder('TerminationMethod','Truncated',
'InitialStateInputPort', true,...
'TrellisStructure', trellis);
Viterbi=comm.ViterbiDecoder('TrellisStructure', trellis,
'InputFormat','Hard','TerminationMethod','Truncated');
CRCGen = comm.CRCGenerator('Polynomial',[1 1 zeros(1, 16) 1 1 0 0 0 1 1]);
CRCDet = comm.CRCDetector ('Polynomial',[1 1 zeros(1, 16) 1 1 0 0 0 1 1]);
end
%% Processing loop modeling transmitter, channel model and receiver
numErrs = 0; numBits = 0; nS=0;
results=zeros(3,1);
while ((numErrs < maxNumErrs) && (numBits < maxNumBits))
% Transmitter
u
= randi([0 1], FRM,1);
% Generate bit payload
u1
= step(CRCGen, u);
% CRC insertion
u2
= u1((end-C+1):end);
% Tail-biting convolutional coding
[, state] = step(ConvEncoder1, u2);
u3
= step(ConvEncoder2, u1,state);
u4
= fcn_RateMatcher(u3, L, codeRate); % Rate matching
u5
= fcn_Scrambler(u4, nS);
% Scrambling
u6
= step(Modulator, u5);
% Modulation
u7
= TransmitDiversityEncoderS(u6);
% MIMO Alamouti encoder
% Channel
[u8, h8] = MIMOFadingChanS(u7);
% MIMO fading channel
noise_var = real(var(u8(:)))/(10.^(0.1*snr));
u9
= step(AWGN, u8, noise_var);
% AWGN
% Receiver
uA
= TransmitDiversityCombinerS(u9, h8);% MIMO Alamouti combiner
uB
= step(DeModulator, uA);
% Demodulation
uC
= fcn_Descrambler(uB, nS);
% Descrambling
uD
= fcn_RateDematcher(uC, L);
% Rate de-matching
uE
= [uD;uD];
% Tail-biting
uF
= step(Viterbi, uE);
% Viterbi decoding
uG
= uF(Index);
y
= step(CRCDet, uG );
% CRC detection
results
= step(BitError, u, y);
% Update number of bit errors

Prototyping as C/C++ Code


460

Understanding LTE with MATLAB460

numErrs = results(2);
numBits = results(3);
nS
= nS + 2; nS = mod(nS, 20);
end
%% Clean up & collect results
ber = results(1); bits= results(3);
reset(BitError);

In order to manage the files and directories associated with C-code generation properly,
we create a new directory in our computer and place all the MATLAB files in it. In this
example, we create a directory called C:\Examples\PDCCH and copy all the files needed
to run the eighth version of the algorithm to it. The MATLAB script performing these tasks
is as fol- lows:

Algorithm
MATLAB script: MATLAB_testbench_directory
%% Create new directory in C:\ drive
PARENTDIR='C:\';
NEWDIR='Examples\PDCCH';
mkdir(PARENTDIR,NEWDIR);
%% Make that your destination directory
DESTDIR=fullfile(PARENTDIR,NEWDIR);
%% Copy 10 necessary files to destination directory
copyfile('Alamouti_DecoderS.m',DESTDIR);
copyfile('Alamouti_EncoderS.m',DESTDIR);
copyfile('fcn_Descrambler.m',DESTDIR);
copyfile('fcn_RateDematcher.m',DESTDIR);
copyfile('fcn_RateMatcher.m',DESTDIR);
copyfile('fcn_Scrambler.m',DESTDIR);
copyfile('MIMOFadingChanS.m',DESTDIR);
copyfile('TransmitDiversityCombinerS.m',DESTDIR);
copyfile('TransmitDiversityEncoderS.m',DESTDIR);
copyfile('zPDCCH_v8.m',DESTDIR);
%% Go to destination directory
cd(DESTDIR);

10.12.2

Executing MATLAB Testbench

At this step we execute two scripts: a build script that generates a MEX function for the
func- tion zPDCCH_v8.m and a calling script, which constitutes our MATLAB testbench.
These scripts can be created in the same destination directory as the MATLAB functions are
stored

Prototyping as C/C++ Code


461

Understanding LTE with MATLAB461

in (C:\Examples\PDCCCH). Using the first script (MATLAB_build_version9.m), we can generate the MEX function of the eighth version of the PDCCH algorithm. The codegen
command for this build script is as follows:

Algorithm
MATLAB script: MATLAB_build_version9
MaxSNR=8;
MaxNumBits=1e7;
MaxNumErrs=MaxNumBits;
fprintf(1,'\nGenerating MEX function for PDCCH algorithm ...\n');
codegen args { MaxSNR, MaxNumErrs, MaxNumBits} zPDCCH_v8 o
zPDCCH_v9 fprintf(1,'Done.\n\n');
MEX_FCN_NAME='zPDCCH_v9';
fprintf(1,'Output MEX function name: %s \n',MEX_FCN_NAME);

The testbench (MATLAB_testbench_version9.m) performs an iterative Eb/N0 parameter


sweep and records the BER values as a function of Eb/N0. The testbench uses eight test
cases, corresponding to Eb/N0 values of 0.5 4.0, increasing in steps of 0.5 dB. We
compute and record the BER value for each Eb/N0 value. The stopping criterion for the
simulation is a predetermined number of processed bits. This is achieved by setting both the
maximum number of errors (MaxNumErrs) and the maximum number of bits (MaxNumBits)
parameters to a single value; for example, 10 million bits. Finally, we record the execution
time of the eight test cases by obtaining and then subtracting the system clock values before
and after the simulation.

Algorithm
MATLAB testbench: MATLAB_testbench_version9
MaxSNR=8;
MaxNumBits=1e7;
MaxNumErrs=1e7;
ber_vector=zeros(MaxSNR,1);
fprintf(1,'\nMATLAB testbench for PDCCH algorithm\n');
fprintf(1,'Maximum number of errors : %9d\n', MaxNumErrs);
fprintf(1,'Maximum number of bits : %9d\n\n', MaxNumBits);
tic;
for snr=1:MaxSNR
fprintf(1,'Iteration number %d\r',snr);
EbNo=snr/2;
ber= zPDCCH_v9(EbNo, MaxNumErrs, MaxNumBits);
ber_vector(snr)=ber;
end

Prototyping as C/C++ Code


462

Understanding LTE with MATLAB462

time_8=toc;
fprintf(1,'\nTime to complete %d iterations = %6.4f (sec)\n\n', MaxSNR, time_8);
for snr = 1:MaxSNR
fprintf(1,'Iteration %2d EbNo %3.1f BER %e\n', snr, snr/2, ber_vector(snr));
end

When we execute this testbench, the results shown in Figure 10.32 are displayed in the
MATLAB command window. Note that we have obtained reference BER values and
simula- tion times by running the MATLAB testbench. We will compare these values with
the results obtained by running the C testbench, which we will create shortly.

Figure 10.32

MATLAB testbench, furnishing reference values for execution time and output values

Prototyping as C/C++ Code


463

10.12.3

Understanding LTE with MATLAB463

Generating C Code

In this step, we generate C code from the function zPDCCH_v8.m using the codegen
command. To generate a static C library we can use either the codegen command or the
MATLAB Coder Project. When using the codegen command line we need only specify lib
as the configuration option, as illustrated in the following script:

Algorithm
MATLAB script: MATLAB_build_version9
MaxSNR=8;
MaxNumBits=2e6;
MaxNumErrs=MaxNumBits;
fprintf(1,'Generating source files (*.c) and header files (*.h) for PDCCH algorithm ...');
codegen args { MaxSNR, MaxNumErrs, MaxNumBits} zPDCCH_v8 config:lib
-report fprintf(1,'Done.');
FCN_NAME='zPDCCH_v8';
Location=fullfile(pwd,'codegen','lib',FCN_NAME);
fprintf(1,'All generated files are in the following directory: \n%s\n', Location);

Upon completion, the codegen command prints a message in the MATLAB command line
that includes a hyperlink to the generated C code. When we click on the hyperlink, we open
the Code Generation Report (Figure 10.33).
All of the C source files and header files are stored in a unique folder under the
Destination directory. In this example, the destination directory is C:\Examples\PDCCH and
all the source files are in a subdirectory called codegen\lib\zPDCCH_v8. Figure 10.34 shows
all the source and header files generated, listed by the ls command.

10.12.4

Entry-Point Functions in C

Having already generated C code from our MATLAB function, the rest of the development
process can be performed completely outside the MATLAB environment. In order to
generate a C executable, otherwise known as a C testbench, all we have to do is to write a
C main function and call the generated entry-point functions in it.
In our example, the entry-point function in MATLAB is zPDCCH_v8.m. The generated
C code will therefore have three header files, which define the entry-point C function
prototypes for: (i) the main entry-point function, (ii) the initialization function, and (iii)
the termination function. These files are zPDCCH_v8.h, zPDCCH_v8_initialize.h, and
zPDCCH_v8_terminate.h, respectively.

Prototyping as C/C++ Code


464

Figure 10.33

Understanding LTE with MATLAB464

Code Generation Report: showing generated code for the zPDCCH_v8 algorithm

Figure 10.34

List of generated C source files and header files

You might also like