%% Bluetooth EDR RF-PHY Transmitter Tests for Modulation Accuracy and Carrier Frequency Stability
% This example shows how to perform Bluetooth® enhanced data rate (EDR) radio frequency (RF) physical layer (PHY) transmitter tests specific to modulation accuracy and carrier frequency stability using the Communications Toolbox™ Library for the Bluetooth Protocol. The test measurements compute the initial frequency offset, root mean square (RMS) differential error vector magnitude (DEVM), and peak DEVM values. This example also verifies whether these test measurement values are within the limits specified by the Bluetooth RF-PHY Test Specifications [1].
%% Objectives of Bluetooth RF-PHY Tests
% The Bluetooth RF-PHY Test Specifications [1] defined by the Bluetooth Special Interest Group (SIG) includes RF-PHY tests for the transmitter and receiver. The objectives of these RF-PHY tests are to:
% Ensure interoperability between all of the Bluetooth devices.
% Ensure a basic level of system performance for all of the Bluetooth products.
% Each test case has a specific test procedure and an expected outcome, that must be achieved by the implementation under test (IUT).
%% RF-PHY Transmitter Tests
% The main goal of the transmitter test measurements is to ensure that the transmitter characteristics are within the limits specified by the Bluetooth RF-PHY Test Specifications [1]. This example includes transmitter tests relevant to EDR modulation accuracy and carrier frequency stability. This table shows various RF-PHY transmitter tests performed in this example.
%
%% RF-PHY Transmitter Test Procedure
% This block diagram summarizes the test procedure for transmitter tests relevant to EDR modulation accuracy and carrier frequency stability of Bluetooth EDR waveforms.
%
% Generate DH or EV packets by using pseudorandom sequences of these lengths.
%
% Pass the payload bits through the bluetoothWaveformGenerator.m function to generate Bluetooth EDR test waveforms.
% Add a carrier frequency offset and drift.
% Add additive white Gaussian noise (AWGN).
% Estimate the initial frequency offset using the basic rate (BR) portion of the waveform.
% Compensate the EDR portion with the estimated initial frequency offset.
% Perform square root raised cosine filtering using the filter whose coefficients are generated based on the Bluetooth RF-PHY Test Specifications [1].
% Divide the EDR portion into blocks of length 50 microseconds each.
% For each block, delay the compensated sequence by 1 microsecond and differentiate the delay with actual compensated sequence to get the error sequence.
% Compute the RMS DEVM and peak DEVM based on the error sequence and compensated sequence.
% Get the test verdict and display the results.
%% Check for Support Package Installation

% Check if the 'Communications Toolbox Library for the Bluetooth Protocol'
% support package is installed or not.
commSupportPackageCheck('BLUETOOTH');

%% Configure Simulation Parameters
% To specify PHY transmission mode, packet type, initial frequency offset, maximum frequency drift, and samples per symbol, set phyMode, packetType, initialFreqOffset, maxFreqDrift, and sps respectively.

phyMode = 'EDR2M';                    % PHY transmission mode
packetType = 'DH1';                 % EDR packet type
initialFreqOffset = 40000; % Initial frequency offset (Hz)
maxFreqDrift = 0;      % Maximum frequency drift (Hz), must be in the range [-10e3, 10e3]
sps = 8;                                           % Samples per symbol

%% Generate Test Parameters
% Use the preceding configured parameters to generate the test parameters. To get all of the test parameters, use the helperEDRModulationTestConfig.m helper function. To add frequency offset and thermal noise, create and configure comm.PhaseFrequencyOffset and comm.ThermalNoise System objects, respectively.

[edrTestParams,waveformConfig,filtCoeff] = helperEDRModulationTestConfig(phyMode,packetType,sps);

% Create frequency offset System object
frequencyDelay = comm.PhaseFrequencyOffset('SampleRate',edrTestParams.sampleRate);

% Create thermal noise System object
NF = 12; % Noise figure (dB)
thNoise = comm.ThermalNoise('NoiseMethod','Noise figure', ...
                            'SampleRate',edrTestParams.sampleRate, ...
                            'NoiseFigure',NF);

%% Simulate Transmitter Tests
% Using the preceding RF-PHY transmitter test procedure, simulate the transmitter tests.

% Initialize variables 
symDEVM = zeros(1,edrTestParams.requiredBlocks*edrTestParams.blockLength);
[blockRMSDEVM,estimatedBlockFreqDrifts] = deal(zeros(1,edrTestParams.requiredBlocks));
estimatedInitFreqOff = zeros(1,edrTestParams.NumPackets);
blockCount = 0;

% Generate 200 blocks of data as specified in Bluetooth RF-PHY Test Specifications
for packetCount = 1:edrTestParams.NumPackets
    
    % Generate random bits
    payload = edrTestParams.pnSeq();
    
    % Generate Bluetooth EDR waveform
    txWaveform = bluetoothWaveformGenerator(payload,waveformConfig);
    
    % Generate ideal EDR symbols from waveform
    packetDuration = helperBluetoothPacketDuration(packetType,phyMode,edrTestParams.numBytes);
    txWaveform1 = txWaveform(1:(packetDuration+edrTestParams.span)*sps);
    idealTxEDRWaveform = txWaveform1((edrTestParams.startIndex)*sps+1:end);
    
    % Perform matched filtering
    rxFilt = upfirdn(idealTxEDRWaveform,filtCoeff,1,sps);
    
    % Remove delay and normalize filtered signal
    idealEDRSymbols = rxFilt(edrTestParams.span+1:end,1)/sqrt(sps);
    
    % Add frequency offset    
    driftRate = maxFreqDrift/((packetDuration+edrTestParams.span)*sps); % Drift rate
    freqDrift = driftRate*(0:1:((packetDuration+edrTestParams.span)*sps-1))';% Frequency drift for the packet
    frequencyDelay.FrequencyOffset = freqDrift + initialFreqOffset; % Frequency offset, includes initial frequency offset and drift
    transWaveformCFO = frequencyDelay(txWaveform(1:(packetDuration+edrTestParams.span)*sps));
    
    % Add thermal noise
    noisyWaveform = thNoise(transWaveformCFO);
            
    % Compute initial frequency offset specified in Bluetooth RF-PHY Test Specifications
    estimatedInitFreqOff(packetCount) = helperEstimateInitialFreqOffset(noisyWaveform,sps);
    
    % Compensate initial frequency offset in the received waveform
    pfOffset = comm.PhaseFrequencyOffset('SampleRate',edrTestParams.sampleRate,'FrequencyOffset',-estimatedInitFreqOff(packetCount));
    freqTimeSyncRcv = pfOffset(noisyWaveform);

    % Remove access code, packet header, and guard time from packet
    rxEDRWaveform = freqTimeSyncRcv((edrTestParams.startIndex)*sps+1:end);
    
    % Perform matched filtering
    rxFilt = upfirdn(rxEDRWaveform,filtCoeff,1,sps);
    receivedEDRSymbols = rxFilt(edrTestParams.span+1:end,1)/sqrt(sps);
    
    % Compute DEVM values
    [rmsDEVM,rmsDEVMSymbol,samplingFreq] = ...
        helperEDRModulationTestMeasurements(receivedEDRSymbols,idealEDRSymbols,edrTestParams);
    
    % Accumulate measured values for 200 blocks as specified in Bluetooth RF-PHY Test Specifications 
    blockCount = blockCount + edrTestParams.numDEVMBlocks;
    symDEVM(((packetCount-1)*edrTestParams.numDEVMBlocks*edrTestParams.blockLength)+1:(packetCount)*edrTestParams.numDEVMBlocks ...
        *edrTestParams.blockLength) = rmsDEVMSymbol(1:edrTestParams.numDEVMBlocks*edrTestParams.blockLength);
    blockRMSDEVM(((packetCount-1)*edrTestParams.numDEVMBlocks)+1:((packetCount)*edrTestParams.numDEVMBlocks)) = ...
        rmsDEVM(1:edrTestParams.numDEVMBlocks);  
    estimatedBlockFreqDrifts(((packetCount-1)*edrTestParams.numDEVMBlocks)+1:((packetCount)*edrTestParams.numDEVMBlocks)) = ...
        samplingFreq(1:edrTestParams.numDEVMBlocks); 
end

% Use the helperEDRModulationTestVerdict.m helper function to verify whether the measurements are within the specified limits and display the verdict.

helperEDRModulationTestVerdict(phyMode, ...
    edrTestParams,estimatedInitFreqOff,symDEVM,blockRMSDEVM,estimatedBlockFreqDrifts)
% Plot the constellation diagram
if strcmp(phyMode,'EDR2M')
    refSymbols = dpskmod(0:edrTestParams.M-1,edrTestParams.M,pi/4,'gray'); % Perform pi/4-DQPSK modulation
else
    refSymbols = dpskmod(0:edrTestParams.M-1,edrTestParams.M,0,'gray'); % Perform 8-DPSK modulation
end
constDiag = comm.ConstellationDiagram('ReferenceConstellation',refSymbols, ...
    'Title','Received EDR Constellation');
constDiag(receivedEDRSymbols);
release(constDiag);

% This example demonstrates the Bluetooth EDR transmitter test measurements specific to modulation accuracy and carrier frequency stability. The simulation results verify that these computed test measurement values are within the limits specified by the Bluetooth RF-PHY Test Specifications [1].
%% Appendix
% The example uses these helpers:
% helperEDRModulationTestConfig.m: Configure Bluetooth test parameters
% helperEstimateInitialFreqOffset.m: Estimate initial frequency offset
% helperEDRModulationTestMeasurements.m: Compute all DEVM measurements required for test
% helperEDRModulationTestVerdict.m: Validate test measurements and display result
%% Selected Bibliography
% Bluetooth Special Interest Group (SIG). “Bluetooth RF-PHY Test Specification”, v1.2/2.0/2.0, EDR/2.1/2.1, EDR/3.0/3.0, HS (), RF.TS/3.0.H.1, Section 4.5. 2009. https://www.bluetooth.com/.
% Bluetooth Special Interest Group (SIG). "Core System Package [BR/EDR Controller Volume]". Bluetooth Core Specification. Version 5.2, Volume 2. https://www.bluetooth.com/.
% Copyright 2020 The MathWorks, Inc.