Main Content

Code Generation of WLAN Toolbox™ Features

This example shows how to generate MEX files and efficient C/C++ code for the WLAN Toolbox™ waveform generator function and verify its correct behaviour. Additionally, it shows how to work around limitations of code generation for WLAN Toolbox channel models. All WLAN Toolbox functions and System objects™ are supported for C/C++ code generation.

Introduction

With MATLAB Coder™, you can generate efficient, portable C source code, standalone executables, and MEX functions for deployment in desktop and embedded applications. You can speed up your MATLAB code using MEX functions or integrate generated source code and static or dynamic libraries into your C/C++ code projects. See Setting Up the C or C++ Compiler (MATLAB Coder) for more information about how to set up the C/C++ compiler. In order to use code generation, you need a MATLAB Coder license.

This example uses the codegen function to generate code for the WLAN Toolbox waveform generator and the TGax channel System object. First, prepare the required input arguments of the waveform generator and configure MATLAB Coder to generate MEX files. Next, compare the output of the generated MEX files and the original MATLAB code. Finally, the example shows how to work around limitations of code generation affecting WLAN Toolbox.

Input Arguments Definition

For code generation, you must specify the size and type of the input arguments to your entry-point function. In this case, you specify the input arguments of the wlanWaveformGenerator function and packet format configuration object. The mandatory arguments of the waveform generator are the data bits of the physical layer service data unit (PSDU) and the waveform format configuration. Additional inputs such as the idle time, scrambler initialization, and window transition time depend on the format configuration. Specify the additional inputs as name-value pairs. See wlanWaveformGenerator for more information.

You can use example values of the input arguments and the codegen function automatically derives their size, class, and complexity. However, the size of the input data vector depends on properties of the format configuration such as the channel bandwidth and coding. Use the coder.typeof function to define a variable-size input data vector that adapts to the format configuration properties as required.

Thus, you can run the generated code for multiple parameter sets of the format configuration object. For more information about specifying variable-size input arguments, see Generate Code for Variable-Size Data (MATLAB Coder). In this case, specify only the first dimension as variable-size.

variableDims = [1 0];

Variable-size vectors can be upper bounded or unbounded. To allow for full flexibility, you can select the upper bound to be the maximum aggregated MAC protocol data unit (A-MPDU) length, i.e., 6500631 bytes.

upperBound = 6500631*8; % Upper bound in bits

Next, use coder.typeof to define an input type as a column vector of doubles with a maximum size of upperBound-by-1, with the first dimension variable-size.

inputBits = coder.typeof(double(0),[upperBound 1],variableDims);

As the inputBits data type is double, you can only use double-precision values for the input bits of the generated MEX and C/C++ code.

Next, create a high-efficiency single-user (HE SU) format configuration object with default parameters and its corresponding configuration structure using the coder.typeof function. Use this structure to specify the type and size of any property of the HE SU format configuration object.

cfgHESU = wlanHESUConfig;
cfgHESUcg = coder.typeof(cfgHESU);

There are two possible forward-error-correction (FEC) coding types for the HE-Data: low-density parity-check, specified by setting the ChannelCoding property of cfgHESU to 'LDPC', and binary convolutional coding, specified as 'BCC'. Since these are character arrays of different lengths, use the coder.typeof function to define a variable-length row vector of maximum size 1-by-4 characters.

cfgHESUcg.Properties.ChannelCoding = coder.typeof('LDPC',[1 4],[0 1]);

Use the same strategy for the channel bandwidth property. In this case, the longest character array corresponds to 'CBW160', so six characters are enough to cover all other possible cases, i.e., 'CBW20', 'CBW40', and 'CBW80'.

cfgHESUcg.Properties.ChannelBandwidth = coder.typeof('CBW160',[1 6],[0 1]);

Specify optional arguments of the waveform generator such as the windowing transition time using name-value pairs. Use coder.Constant to define the name of the argument because it is a string literal that is not expected to change.

WindowTransitionTime_Name = coder.Constant('WindowTransitionTime');

Use an example value from which the codegen function derives its type and size. This technique is only suitable for fixed-size input arguments.

WindowTransitionTime_Value = 0;

Code Generation for the WLAN Toolbox Waveform Generator

Once the input arguments are specified for code generation, configure MATLAB Coder to generate MEX files and C/C++ code. A MEX file acts as an interface to the generated C/C++ code that can run in MATLAB. MEX file generation is usually the first step in the code generation workflow as it provides a convenient way for verifying the generated C/C++ code.

You can generate a MEX file, C/C++ code, a dynamic library, or a standalone executable by creating a MATLAB Coder configuration object and specifying the build type as 'MEX', 'LIB', 'DLL', or 'EXE', respectively.

BuildType = 'MEX';
cfgCoder = coder.config(BuildType);

Generate a report containing useful information about the code generation process.

cfgCoder.GenerateReport = true;

The name of the generated MEX file is the entry-point function name appended by the suffix 'mex', that is, wlanWaveformGenerator_mex. To specify a different name for your MEX file, use the option -o output_file_name. You can find the generated MEX files in your local folder and the generated C/C++ code in the folder codegen\mex\wlanWaveformGenerator.

Users of Microsoft Visual C++ product family may see the C4101 compiler warning indicating an unreferenced local variable.

inputArgs = {inputBits,cfgHESUcg,WindowTransitionTime_Name,WindowTransitionTime_Value}; %#ok<NASGU>
codegen wlanWaveformGenerator -args inputArgs -config cfgCoder -o wlanWaveformGenerator_HESU_mex
Code generation successful: To view the report, open('codegen/mex/wlanWaveformGenerator/html/report.mldatx')

Next, verify that the generated MEX file behaves as expected when you use different configurations of the ChannelBandwidth and ChannelCoding by comparing its output to that of the wlanWaveformGenerator.

% Create a HE SU format configuration object specifying the channel
% bandwidth, coding, number of antennas and streams.
cfgHESU = wlanHESUConfig('ChannelBandwidth','CBW20','ChannelCoding','BCC', ...
                         'NumTransmitAntennas',2,'NumSpaceTimeStreams',2);

% Set the value of the window transition time
WindowTransitionTime = 1e-09;

% Create a PSDU of size defined by the getPSDULength function
inputBits = randi([0 1],getPSDULength(cfgHESU)*8,1);

% Run the wlanWaveformGenerator
waveformMAT = wlanWaveformGenerator(inputBits,cfgHESU,'WindowTransitionTime',WindowTransitionTime);

% Run the generated MEX file
waveformMEX = wlanWaveformGenerator_HESU_mex(inputBits,cfgHESU,'WindowTransitionTime',WindowTransitionTime);

% Compare the outputs of the wlanWaveformGenerator and generated MEX file
difference = waveformMAT - waveformMEX;

% Check the results are consistent
if max(abs(difference),[],'all') > 1e-10
    error('The MEX file generated does not produce the same results as wlanWaveformGenerator.')
else
    disp('The outputs of the generated MEX file and the wlanWaveformGenerator are equal.')
end
The outputs of the generated MEX file and the wlanWaveformGenerator are equal.

Additional Options for Code Generation

In addition to the reporting options used above, you can configure MATLAB Coder with more advanced options.

  • Generate C/C++ code only but do not build object code or MEX files setting cfgCoder.GenCodeOnly = true. This can save time when you iterate between modifying MATLAB code and inspecting the generated C/C++ code. To generate a MEX file, set this value to false.

  • Configure MATLAB Coder for optimized C/C++ code generation by setting cfgCoder.BuildConfiguration = 'Faster Runs'. This option is available only for 'LIB', 'DLL', and 'EXE' build types.

See the coder.config (MATLAB Coder) reference page for more information.

Limitations of Code Generation

WLAN Channel Models are System objects, which are designed specifically for implementing and simulating dynamic systems with inputs that change over time. Consider these limitations for code generation of System objects:

  • Nontunable property values must be constant and can only be assigned once before a step method is executed, including the assignment in the constructor.

  • You cannot pass in a System object™ to an entry-point function.

See System Objects in MATLAB Code Generation (MATLAB Coder) for more information about rules and limitations of System objects™ for code generation.

If you try to generate code for the entry-point function named hCustomChannelNT, which creates a wlanTGaxChannel with a bandwidth specified by the input argument BW and filters the signal inputSignal, the code generation process fails.

function signalOut = hCustomChannelNT(BW, signalIn)
   
    % Create a TGax channel with the appropriate bandwidth 
    ch = wlanTGaxChannel('ChannelBandwidth',BW);
    % Filter the input signal
    signalOut = ch(signalIn); 
    
end

The error message indicates: Failed to compute constant value for nontunable property 'ChannelBandwidth'.

The ChannelBandwidth property of the wlanTGaxChannel object is not a constant value because it depends on the input argument BW of the hCustomChannelNT function. You can work around this by setting BW to be a constant value.

inputSignal = coder.typeof(complex(0),[Inf 1],[1 0]); %#ok<NASGU>
codegen hCustomChannelNT -args {coder.Constant('CBW160'),inputSignal};
Code generation successful.

However, if you specify a constant value for the channel bandwidth, you cannot change the channel bandwidth at runtime. The following call hCustomChannelNT_mex('CBW20',inputSignal) fails because the specified argument BW is not 'CBW160'. It is possible to work around this for a limited variability of the input arguments using a switch-case block. The function hCustomChannel contains a switch-case where each of the cases creates a wlanTGaxChannel with the appropriate channel bandwidth.

function signalOut = hCustomChannel(ChannelBandwidth, signalIn)
    
    % Create a TGax channel with the appropriate bandwidth and filter the input signal
    switch ChannelBandwidth
        case 'CBW20'
            ch = wlanTGaxChannel('ChannelBandwidth','CBW20');
            signalOut = ch(signalIn);
        case 'CBW40'
            ch = wlanTGaxChannel('ChannelBandwidth','CBW40');
            signalOut = ch(signalIn);
        case 'CBW80'
            ch = wlanTGaxChannel('ChannelBandwidth','CBW80');
            signalOut = ch(signalIn);
        case 'CBW160'
            ch = wlanTGaxChannel('ChannelBandwidth','CBW160');
            signalOut = ch(signalIn);
        otherwise
            error('Invalid bandwidth configuration.')
    end
    
end

Note that hCustomChannel creates a new channel object every time it is used, so it does not preserve the state of the channel.

Next, generate code for hCustomChannel and select multiple channel bandwidths at runtime.

inputSignal = coder.typeof(complex(0),[Inf 1],[1 0]);
BW = coder.typeof('CBW160',[1 6],[0 1]);
inputArgs = {BW,inputSignal};
codegen hCustomChannel -args inputArgs

cfgHESU = wlanHESUConfig;
cfgHESU.ChannelBandwidth = 'CBW20';

inputSignal = wlanWaveformGenerator_HESU_mex([1 0 1]', cfgHESU,'WindowTransitionTime',0);

rng('default') % Set the default random number generator for reproduction purposes
outputSignalMEX = hCustomChannel_mex('CBW20',inputSignal);
rng('default')
outputSignalMAT = hCustomChannel('CBW20',inputSignal);

% Calculate the difference between the MEX and MATLAB files outputs
difference = outputSignalMAT - outputSignalMEX;

% Check the results are consistent
if max(abs(difference),[],'all') > 1e-10
    error('The generated MEX file does not produce the same results as hCustomChannel.')
else
    disp('The outputs of the generated MEX file and hCustomChannel are equal.')
end
Code generation successful.

The outputs of the generated MEX file and hCustomChannel are equal.

Change the channel bandwidth and pass the signal through the channel.

cfgHESU.ChannelBandwidth = 'CBW40';
inputSignal = wlanWaveformGenerator_HESU_mex([1 0 1]', cfgHESU,'WindowTransitionTime',0);

rng('default') % Set the default random number generator for reproduction purposes
outputSignalMEX = hCustomChannel_mex('CBW40',inputSignal);
rng('default')
outputSignalMAT = hCustomChannel('CBW40',inputSignal);

% Calculate the difference between the MEX and MATLAB files outputs
difference = outputSignalMAT - outputSignalMEX;

% Check the results are consistent
if max(abs(difference),[],'all') > 1e-10
    error('The MEX file generated does not produce the same results as hCustomChannel.')
else
    disp('The outputs of the generated MEX file and hCustomChannel are equal.')
end
The outputs of the generated MEX file and hCustomChannel are equal.

Further Investigation

You can integrate the generated code with the SystemVerilog Direct Programming Interface (DPI) to export MATLAB algorithms to ASIC or FPGA verification environments including Synopsys VCS®, Cadence Incisive or Xcelium, and Mentor Graphics ModelSim or Questa. You can automatically generate SystemVerilog DPI components from MATLAB functions using MATLAB Coder™ with HDL Verifier™. The following workflow can be used with MATLAB functions that generate stimuli and perform analysis or with a MATLAB function that is a behavioral golden reference for the DUT (Device Under Test) in the ASIC or FPGA verification environment. See SystemVerilog DPI Component Generation (HDL Verifier) (HDL Verifier) to learn more.