Main Content


Quadrature amplitude demodulation



Z = qamdemod(Y,M) returns a demodulated signal, Z, given quadrature amplitude modulation (QAM) signal Y of modulation order M.


Z = qamdemod(Y,M,symOrder) returns a demodulated signal, Z, and specifies the symbol order for the demodulation.


Z = qamdemod(___,Name=Value) specifies options using one or more name-value arguments. For example, OutputType=bit sets the type of output signal to bits.


collapse all

Demodulate an 8-QAM signal and plot the points corresponding to symbols 0 and 3.

Generate random 8-ary data symbols.

data = randi([0 7],1000,1);

Modulate data by applying 8-QAM.

txSig = qammod(data,8);

Pass the modulated signal through an AWGN channel.

rxSig = awgn(txSig,18,'measured');

Demodulate the received signal using an initial phase of π/8.

rxData = qamdemod(rxSig.*exp(-1i*pi/8),8);

Generate the reference constellation points.

refpts = qammod((0:7)',8) .* exp(1i*pi/8);

Plot the received signal points corresponding to symbols 0 and 3 and overlay the reference constellation. The received data corresponding to those symbols is displayed.

hold on
legend('Points corresponding to 0','Points corresponding to 3', ...
    'Reference constellation','location','nw');

Figure contains an axes object. The axes object with xlabel In-Phase, ylabel Quadrature contains 11 objects of type line, text. One or more of the lines displays its values using only markers These objects represent Points corresponding to 0, Points corresponding to 3, Reference constellation.

Modulate and demodulate random data by using 16-QAM with WLAN symbol mapping. Verify that the input data symbols match the demodulated symbols.

Generate a 3-D array of random symbols.

x = randi([0,15],20,4,2);

Create a custom symbol mapping for the 16-QAM constellation based on WLAN standards.

wlanSymMap = [2 3 1 0 6 7 5 4 14 15 13 12 10 11 9 8];

Modulate the data, and set the constellation to have unit average signal power. Plot the constellation.

y = qammod(x,16,wlanSymMap, ...
    UnitAveragePower=true, ...

Figure contains an axes object. The axes object with title 16-QAM, Custom Mapping, UnitAveragePower=true, xlabel In-phase Amplitude, ylabel Quadrature Amplitude contains 19 objects of type line, text. One or more of the lines displays its values using only markers

Demodulate the received signal.

z = qamdemod(y,16,wlanSymMap, ...

Verify that the demodulated signal is equal to the original data.

ans = logical

Demodulate a fixed-point QAM signal and verify that the data is recovered correctly.

Set the modulation order as 64, and determine the number of bits per symbol.

M = 64;
bitsPerSym = log2(M);

Generate random bits. When operating in bit mode, the length of the input data must be an integer multiple of the number of bits per symbol.

x = randi([0 1],10*bitsPerSym,1);

Modulate the input data using a binary symbol mapping. Set the modulator to output fixed-point data. The numeric data type is signed with a 16-bit word length and a 10-bit fraction length.

y = qammod(x,M,'bin', ...
    InputType='bit', ...

Demodulate the 64-QAM signal. Verify that the demodulated data matches the input data.

z = qamdemod(y,M,'bin',OutputType='bit');
s = isequal(x,double(z))
s = logical

Estimate bit error rate (BER) performance for hard-decision and soft-decision Viterbi decoders in AWGN. Compare the performance to that of an uncoded 64-QAM link.

Set the simulation parameters.

rng default
M = 64;                % Modulation order
k = log2(M);           % Bits per symbol
EbNoVec = (4:10)';     % Eb/No values (dB)
numSymPerFrame = 1000; % Number of QAM symbols per frame

Initialize the BER results vectors.

berEstSoft = zeros(size(EbNoVec)); 
berEstHard = zeros(size(EbNoVec));

Set the trellis structure and traceback depth for a rate 1/2, constraint length 7, convolutional code.

trellis = poly2trellis(7,[171 133]);
tbl = 32;
rate = 1/2;

The main processing loops perform these steps:

  • Generate binary data

  • Convolutionally encode the data

  • Apply QAM modulation to the data symbols. Specify unit average power for the transmitted signal

  • Pass the modulated signal through an AWGN channel

  • Demodulate the received signal using hard decision and approximate LLR methods. Specify unit average power for the received signal

  • Viterbi decode the signals using hard and unquantized methods

  • Calculate the number of bit errors

The while loop continues to process data until either 100 errors are encountered or 107 bits are transmitted.

for n = 1:length(EbNoVec)
    % Convert Eb/No to SNR
    snrdB = EbNoVec(n) + 10*log10(k*rate);
    % Noise variance calculation for unity average signal power
    noiseVar = 10.^(-snrdB/10);
    % Reset the error and bit counters
    [numErrsSoft,numErrsHard,numBits] = deal(0);
    while numErrsSoft < 100 && numBits < 1e7
        % Generate binary data and convert to symbols
        dataIn = randi([0 1],numSymPerFrame*k,1);
        % Convolutionally encode the data
        dataEnc = convenc(dataIn,trellis);
        % QAM modulate
        txSig = qammod(dataEnc,M, ...
            InputType='bit', ...
        % Pass through AWGN channel
        rxSig = awgn(txSig,snrdB,'measured');
        % Demodulate the noisy signal using hard decision (bit) and
        % soft decision (approximate LLR) approaches.
        rxDataHard = qamdemod(rxSig,M, ...
            OutputType='bit', ...
        rxDataSoft = qamdemod(rxSig,M, ...
            OutputType='approxllr', ...
            UnitAveragePower=true, ...
        % Viterbi decode the demodulated data
        dataHard = vitdec(rxDataHard,trellis,tbl,'cont','hard');
        dataSoft = vitdec(rxDataSoft,trellis,tbl,'cont','unquant');
        % Calculate the number of bit errors in the frame. 
        % Adjust for the decoding delay, which is equal to 
        % the traceback depth.
        numErrsInFrameHard = ...
        numErrsInFrameSoft = ...
        % Increment the error and bit counters
        numErrsHard = numErrsHard + numErrsInFrameHard;
        numErrsSoft = numErrsSoft + numErrsInFrameSoft;
        numBits = numBits + numSymPerFrame*k;

    % Estimate the BER for both methods
    berEstSoft(n) = numErrsSoft/numBits;
    berEstHard(n) = numErrsHard/numBits;

Plot the estimated hard and soft BER data. Plot the theoretical performance for an uncoded 64-QAM channel.

semilogy(EbNoVec,[berEstSoft berEstHard],'-*')
hold on
xlabel('Eb/No (dB)')
ylabel('Bit Error Rate')

Figure contains an axes object. The axes object with xlabel Eb/No (dB), ylabel Bit Error Rate contains 3 objects of type line. These objects represent Soft, Hard, Uncoded.

As expected, the soft decision decoding produces the best results.

Use the qamdemod function to simulate soft decision output for OQPSK-modulated signals.

Generate an OQPSK modulated signal.

sps = 4;
msg = randi([0 1],1000,1);
oqpskMod = comm.OQPSKModulator( ...
    SamplesPerSymbol=sps, ...
oqpskSig = oqpskMod(msg);

Add noise to the generated signal.

impairedSig = awgn(oqpskSig,15);

Perform Soft-Decision Demodulation

Create QPSK equivalent signal to align in-phase and quadrature.

impairedQPSK = complex( ...
    real(impairedSig(1+sps/2:end-sps/2)), ...

Apply matched filtering to the received OQPSK signal.

halfSinePulse = sin(0:pi/sps:(sps)*pi/sps);
matchedFilter = dsp.FIRDecimator(sps,halfSinePulse, ...
filteredQPSK = matchedFilter(impairedQPSK);

To perform soft demodulation of the filtered OQPSK signal use the qamdemod function. Align symbol mapping of qamdemod with the symbol mapping used by the comm.OQPSKModulator, then demodulate the signal.

oqpskModSymbolMapping = [1 3 0 2];
demodulated = qamdemod(filteredQPSK,4,oqpskModSymbolMapping, ...

Input Arguments

collapse all

Input signal that resulted QAM, specified as a scalar, vector, matrix, or 3-D array of complex values. Each column in the matrix and 3-D array is considered as an independent channel.

Data Types: double | single | fi
Complex Number Support: Yes

Modulation order, specified as a positive integer power of two. The modulation order specifies the number of points in the signal constellation.

Data Types: double | single | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Symbol order, specified as one of these options:

  • 'gray' — Use Gray-coded ordering. For more information, see Gray Code.

  • 'bin' — Use binary-coded ordering.

  • Vector — Use custom symbol ordering. The vector must be of length M. Vectors must use unique elements values in the range [0, (M – 1)]. The first element corresponds to the upper left point of the constellation, with subsequent elements running down column-wise from left to right.

Data Types: string | char | double | single | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Name-Value Arguments

Specify optional pairs of arguments as Name1=Value1,...,NameN=ValueN, where Name is the argument name and Value is the corresponding value. Name-value arguments must appear after other arguments, but the order of the pairs does not matter.

Before R2021a, use commas to separate each name and value, and enclose Name in quotes.

Example: Z = qamdemod(Y,M,symOrder,'OutputType','bit')

Option to scale constellation to unit average power, specified as a numeric or logical 0 (false) or 1 (true).

  • When set to true, the function scales the constellation to the average power of one watt referenced to 1 ohm.

  • When set to false, the function scales the constellation so that the QAM constellation points are separated by a minimum distance of two.

Type of output, specified as 'integer', 'bit', 'llr', or 'approxllr'.

Noise variance, specified as a positive scalar or a vector of positive values. When you set this argument to a:

  • Positive scalar — The same noise variance value is used on all input elements.

  • Vector of positive values — The vector length must be equal to the number of elements in the last dimension of the input signal. Each element of the vector specifies the noise variance for all the elements of the input along the corresponding last dimension.


The exact LLR algorithm computes exponentials using finite precision arithmetic. For computations involving very large positive or negative magnitudes, the exact LLR algorithm yields:

  • Inf or -Inf if the noise variance is a very large value

  • NaN if the noise variance and signal power are both very small values

The approximate LLR algorithm does not compute exponentials. You can avoid Inf, -Inf, and NaN results by using the approximate LLR algorithm.


To enable this name-value pair argument, set OutputType is 'llr' or 'approxllr'.

Option to plot constellation, specified as a numeric or logical 0 (false) or 1 (true) To plot the QAM constellation, specify PlotConstellation=true.

Output Arguments

collapse all

Demodulated output signal, returned as a scalar, vector, matrix, or 3-D array. The data type is the same as that of the input signal, Y. The value and dimension of this output vary depending on the specified OutputType value, as shown in this table.

'OutputType'Return Value of qamdemodDimensions of Output
'integer'Demodulated integer values in the range [0, (M – 1)]Z has the same dimensions as input Y.
'bit'Demodulated bitsThe number of rows in Z is log2(M) times the number of rows in Y. Each demodulated symbol is mapped to a group of log2(M) bits, where the first bit represents the most significant bit (MSB) and the last bit represents the least significant bit (LSB).
'llr'Log-likelihood ratio value for each bit calculated using the Exact Log Likelihood algorithm. For more details, see Exact LLR Algorithm.
'approxllr'Approximate log-likelihood ratio value for each bit. The values are calculated using the Approximate Log Likelihood algorithm. For more details, see Approximate LLR Algorithm.

More About

collapse all

Gray Code

A Gray code, also known as a reflected binary code, is a system where the bit patterns in adjacent constellation points differ by only one bit.

Extended Capabilities

C/C++ Code Generation
Generate C and C++ code using MATLAB® Coder™.

Version History

Introduced before R2006a

expand all