Main Content

Bluetooth LE Packet Error Rate Report Integrity Tests

This example shows how to test the packet error rate (PER) report integrity of a Bluetooth® low energy (LE) radio frequency (RF) physical layer (PHY) receiver, according to the Bluetooth RF-PHY Test Specification [2]. In this example, you also verify whether these test measurement values are within the limits specified by the Bluetooth RF-PHY Test Specification [2].

Objectives of Bluetooth LE RF-PHY Tests

The Bluetooth RF-PHY Test Specification [2] defined by Bluetooth Special Interest Group (SIG) includes RF-PHY tests for both transmitter and receiver. The objectives of these RF-PHY tests are to:

  • Ensure interoperability between all Bluetooth devices

  • Ensure a basic level of system performance for all Bluetooth products

Each test case has a specified test procedure and an expected outcome, which the implementation under test (IUT) must meet.

RF-PHY Receiver Tests

This example deliberately introduces error in the cyclic redundancy check (CRC) field of every alternating packet. The receiver must properly handle the packets with predefined errors. The PER report integrity test validates the error correction mechanism of the receiver. This table shows the test case IDs considered in this example.

Test Ids for PER Report Integrity Tests and respective PHY transmission modes.

This block diagram summarizes the example workflow.

Bluetooth LE Packet Error Rate Report Integrity Test Block diagram.

To simulate the interference tests, perform these steps.

  1. Generate Bluetooth LE test protocol data units (PDUs).

  2. Generate CRC coding configuration object by using crcConfig function.

  3. Add a 24-bit CRC field by using the crcGenerate function.

  4. Corrupt the CRC field in every alternate packet.

  5. Generate a Bluetooth LE test waveform by using the bleWaveformGenerator.

  6. Obtain a passband signal by performing frequency upconversion on the generated test waveform.

  7. Scale the passband signal to a desired input level.

  8. Add white Gaussian noise (AWGN) to the passband signal.

  9. Downconvert the received noisy signal.

  10. Validate the downconverted waveform by using bluetoothTestWaveformValidate function.

  11. Calculate PER on the received payload.

  12. Compare the obtained PER with the reference PER and determine the test verdict.

Initialize the Simulation Parameters

Specify the test value as "PER report integrity".

testValue = "PER report integrity";

Specify the PHY transmission mode, frequency of operation, payload length, length of frequency pulse shape and modulation index.

phyMode = 'LE1M';
Fc = 2440e6;                                   % Hz
payloadLength = 37;     % Bytes, must be in the range [37,255]
pulseLength = 2;         % Length of the frequency pulse shape in the range [1,4]
modulationIndex =0.5;   % Modulation index of GFSK in the range [0.45,0.55]

Specify number of samples per symbol, minimum of 40 samples per symbol as per the test specifications.

sps = 40;

Based on the PHY transmission mode, compute the sampling rate.

sampleRate = 1e6*(1+1*(phyMode=="LE2M"))*sps;

According to the Bluetooth RF-PHY Test Specification [2], the total number of packets required for testing must be an even number in the range [100, 1500]. Set the number of packets for which the simulation must run.

packetCount = 20;

Generate Test Packet PDU

Generate a PRBS9 sequence for the specified payload.

pnSeq = comm.PNSequence(Polynomial = "z^9+z^5+1", ...
    InitialConditions = ones(1,9), ...
    SamplesPerFrame = payloadLength*8);
payload = pnSeq();

Generate test packet PDU by prepending PDU header and length bits field to payload.

pduHeader = zeros(8,1);
pduLengthBits = int2bit(payloadLength,8,false);      % In bits
testPacketPDU = [pduHeader;pduLengthBits;payload];

Generate a synchronization word for the test packet to use as an access address.

syncWord = flip([1 0 0 1 0 1 0 0 1 0 0 0 0 0 1 0 0 1 1 0 1 1 1 0 1 0 0 0 1 1 1 0].');

Initialize a CRC coding configuration object by using crcConfig function.

crcCfg = crcConfig(Polynomial="x^24 + x^10 + x^9 + x^6 + x^4 + x^3 + x + 1", ...
    InitialConditions=int2bit(hex2dec("555555"),24)', ...
    DirectMethod=true);

Define interpolation factor for up-conversion.

interpFactor = ceil(2*Fc/sampleRate)+1;

Create a dsp.DigitalUpConverter (DSP System Toolbox) System object™.

upConv = dsp.DigitalUpConverter(InterpolationFactor = interpFactor, ...
    SampleRate = sampleRate, ...
    Bandwidth = 2e6, ...
    StopbandAttenuation = 44, ...
    PassbandRipple = 0.5, ...
    CenterFrequency = Fc);

Create a dsp.DigitalDownConverter (DSP System Toolbox) System object™.

downConv = dsp.DigitalDownConverter(DecimationFactor = interpFactor, ...
    SampleRate = sampleRate*interpFactor, ...
    Bandwidth = 2e6, ...
    StopbandAttenuation = 44, ...
    PassbandRipple = 0.5, ...
    CenterFrequency = Fc);

In this simulation, the receiver processes a test signal with a specified input level in dBm. Specify the receiver sensitivity in dBm.

switch phyMode
    case "LE1M"
        rxSensitivity = -70 ; % [-70,-104] dBm
    case "LE2M"
        rxSensitivity = -70 ; % [-70,-104] dBm
    case "LE500K"
        rxSensitivity = -75;  % [-70,-108] dBm
    case "LE125K"
        rxSensitivity = -82;  % [-70,-110] dBm
end

Configure the RF-PHY test configuration by using the bluetoothRFPHYTestConfig object.

configObject = bluetoothRFPHYTestConfig(Test=testValue, ...
    Mode=phyMode, ...
    SamplesPerSymbol=sps, ...
    PayloadLength=payloadLength, ...
    PulseLength=pulseLength, ...
    ModulationIndex=modulationIndex);                             

Calculate the input signal scaling factor required to generate signal at the desired input level.

sigLevel = -30;                               % dBm
testInputLevels = rxSensitivity + sigLevel;   % dBm
scalingFactor = 10^((testInputLevels-30)/20); % Input signal amplitude scaling factor

Specify noise figure, ambient temperature, bandwidth, and Boltzmann constant values.

NF = 6;                                       % dB
T = 290;                                      % K
BW = 2e6;                                     % Hz
k = 1.3806e-23;                               % J/K

Use thermal noise to simulate the noise floor of the receiver. The height of the noise floor determines the SNR at the receiver. The noise figure of the receiver determines the level of the noise floor. Compute and display the noise floor and determine the SNR at the receiver.

noiseFloor = 10*log10(k*T*BW) + NF;           % dB
disp("Receiver noise floor: " + num2str(100+30,"%2.1f") + " dBm");
Receiver noise floor: 130.0 dBm
snrdB = -noiseFloor;

Initialize counter for packets in error

packetsError = 0;

Simulate PER Report Integrity Test

Simulated each Bluetooth LE test waveform by appending the corrupted CRC to the test packet. Perform frequency up-conversion on the test waveform. Add white Gaussian noise to the modulated waveform. Perform frequency down conversion and validate the received waveform by using bluetoothTestWaveformValidate function.

for n = 1:packetCount
    % CRC error position
    crcErrPos = randi([1 24],3,~rem(n,2));

    % Append the CRC field to the test packet PDU
    pduCRC = crcGenerate(testPacketPDU,crcCfg);

    % Corrupt the CRC value of every alternating packet
    pduCRC(length(testPacketPDU)+crcErrPos) = ~pduCRC(length(testPacketPDU)+crcErrPos);

    % Generate a Bluetooth LE test waveform from the test packet PDU
    testWaveform = bleWaveformGenerator(pduCRC(:,1), ...
        AccessAddress = syncWord, ...
        SamplesPerSymbol = sps, ...
        Mode = phyMode, ...
        WhitenStatus = "Off", ...
        PulseLength = pulseLength, ...
        ModulationIndex = modulationIndex);

    % Perform frequency up conversion on the test waveform and scale it to
    % the appropriate amplitude level
    waveformUpConverted = scalingFactor*upConv(testWaveform);

    % Add white Gaussian noise to the modulated waveform
    noisyWaveform = awgn(complex(waveformUpConverted),snrdB,"measured");

    % Perform frequency down conversion on the noisy waveform
    waveformDownConverted = downConv(real(noisyWaveform));

    % Validate the down converted waveform and check for CRC fail
    crcError = bluetoothTestWaveformValidate(waveformDownConverted,configObject);

    % Increment the packet in error if CRC is failed
    packetsError = packetsError + crcError;
end

Determine the PER.

per = packetsError/packetCount;

Compare Results to Reference Values

Compare the calculated PER value with the reference PER value and display the test verdict.

[~,refPER] = helperBLEReferenceResults(phyMode,payloadLength);
fprintf("Measured PER is %1.4f. For a payload length of %d bytes, this value must be in the range [%1.4f, %1.4f].\n",per,payloadLength,0.5,(0.5+refPER/2));
Measured PER is 0.5000. For a payload length of 37 bytes, this value must be in the range [0.5000, 0.6540].
if per >= 0.5 && per < (0.5+refPER/2)
    fprintf("PER report integrity test passed.\n");
else
    fprintf("PER report integrity test failed.\n");
end
PER report integrity test passed.

Appendix

This example uses the following helper function:

Selected Bibliography

  1. Bluetooth Special Interest Group (SIG), Inc. “Bluetooth® Technology Website – The Official Website for the Bluetooth Wireless Technology. Get up to Date Specifications, News, and Development Info.” Accessed May 24, 2023. https://www.bluetooth.com/.

  2. Bluetooth Special Interest Group (SIG), Inc. “Core Specification – Bluetooth® Technology Website.” Accessed May 24, 2023. https://www.bluetooth.com/specifications/specs/core-specification-5-3/.