Matlab Generate Ble Waveform
MathWorksOfficialCreated by MathWorks
- Skill
- Tool integration
- Science and research
- BSD-2-Clause
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to generating, simulating, and analyzing Bluetooth Low Energy (BLE) physical layer waveforms. It covers the use of core MATLAB functions such as bleWaveformGenerator, bleIdealReceiver, and bleAngleEstimate to support tasks ranging from basic waveform creation to complex direction-finding (CTE) pipelines, RF-PHY compliance testing, and BER simulations. The skill emphasizes correct configuration for LE1M, LE2M, and Coded PHY modes while adhering to Bluetooth 5.1+ specifications.
What it does
- Generates BLE PHY waveforms for LE1M, LE2M, LE500K, and LE125K modes.
- Simulates direction-finding pipelines using Constant Tone Extension (CTE) for AoA/AoD.
- Performs RF-PHY compliance testing and transmitter measurements like PAPR and OBW.
- Models receiver performance through BER simulations and WLAN coexistence scenarios.
- Configures advertising and data channel PDUs with custom access addresses and whitening.
- Provides visualization patterns for IQ samples and spectral analysis.
When to use it
- When generating BLE PHY waveforms for simulation or testing.
- When implementing direction-finding (AoA/AoD) using CTE.
- When performing RF-PHY compliance or transmitter performance measurements.
- When simulating receiver sensitivity and BER under noise or interference.
- When comparing different BLE PHY modes or analyzing spectral characteristics.
Advantages
- Ensures adherence to BLE specification constraints regarding PHY modes and channels.
- Provides standardized patterns for complex tasks like CTE pipelines and multi-packet bursts.
- Prevents common API hallucinations by enforcing correct parameter usage.
- Includes robust conventions for spectral analysis and visualization.
- Facilitates accurate simulation of practical receiver impairments.
Usage examples
- “Generate an LE2M BLE waveform for channel 15 with a random payload.”
- The agent provides a script using bleWaveformGenerator with Mode set to 'LE2M' and ChannelIndex set to 15, ensuring the symbol rate is correctly calculated as 2 Msym/s.
- “How do I simulate a CTE connection-oriented packet for direction finding?”
- The agent provides a code snippet using bleWaveformGenerator with DFPacketType set to 'ConnectionCTE', followed by the appropriate IQ sampling and angle estimation workflow.
- “Show me how to calculate the Bit Error Rate for an LE1M signal.”
- The agent generates a loop-based script that iterates through SNR values, applies AWGN to the generated waveform, and uses bleIdealReceiver to calculate the error rate.
- “Can I use LE2M for advertising on channel 37?”
- The agent correctly identifies this as a specification violation and refuses the request, explaining that advertising channels (37-39) are restricted to LE1M or Coded PHYs.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/matlab/matlab-generate-ble-waveform/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip matlab-generate-ble-waveform.zip -d .agents/skills
Documentation by MathWorks
BLE Waveform Generation
Routing
| Intent | Cues | Pattern |
|---|---|---|
| Basic generation | "generate", "waveform" | Single-Mode |
| Compare modes | "compare", "all modes" | All-Mode |
| Direction finding | "CTE", "AoA", "AoD" | CTE |
| RF-PHY compliance | "compliance", "RF-PHY" | RF-PHY Test |
| Coexistence | "WLAN", "interference" | WLAN Coexistence |
| TX measurements | "PAPR", "OBW", "power" | TX Measurements |
| Localization | "RSSI", "beacon", "distance" | RSSI Localization |
| BER/receiver | "BER", "noise", "sensitivity" | BER Simulation |
| Multi-packet | "burst", "IFS" | Multi-Packet |
| Spectrum | "spectrum", "spectral mask" | Spectral Analysis |
| Whitening | "whitening", "scrambling" | Whitening Comparison |
| Impairments | "CFO", "practical", "realistic" | End-to-End |
Default (ambiguous request): LE1M, 37-byte payload, channel 37.
When To Use
Use this skill when the user asks to generate, simulate, or analyze BLE PHY-layer waveforms — including mode comparisons, CTE/direction finding, RF-PHY compliance testing, BER simulations, TX measurements, WLAN coexistence, or RSSI localization. Applies to any task involving bleWaveformGenerator, bleIdealReceiver, bleCTEIQSample, bleAngleEstimate, or bluetoothTestWaveform.
When Not To Use
BR/EDR (Classic Bluetooth) → use
bluetoothWaveformGenerator(covered by a separate BR/EDR skill)Channel Sounding (CS) → use
bleCSWaveform(bleCSConfig)(R2024b+); CS has its own ranging/distance-measurement pipeline and is not part of PHY waveform generationNetwork-level simulation → use
bluetoothLENodefor link-layer/network modelingPath loss modeling → use
bluetoothPathLossfor propagation/channel modeling
PHY Modes
| Mode | symbolRate | Data Rate | Coding | Duration (37 B) |
|---|---|---|---|---|
"LE1M" | 1e6 | 1 Mbps | None | ~336 us |
"LE2M" | 2e6 | 2 Mbps | None | ~172 us |
"LE500K" | 1e6 | 500 kbps | FEC S=2 | ~974 us |
"LE125K" | 1e6 | 125 kbps | FEC S=8 | ~2768 us |
References
For detailed guidance beyond what's in this file, see:
functionalAPI.md — Full API reference for bleWaveformGenerator Name-Value pairs
phy-modes-and-timing.md — Detailed timing calculations per PHY mode
cte-direction-finding.md — CTE pipeline: generation, IQ sampling, constraints
direction-finding.md — AoA/AoD angle estimation with bleAngleEstimate
rfphy-compliance-testing.md — RF-PHY test waveform patterns and config
transmitter-measurements.md — OBW, PAPR, power measurement patterns
practical-receiver-simulation.md — BER simulation and impaired receiver
wlan-coexistence.md — WLAN interference and coexistence scenarios
rssi-localization.md — RSSI beacon and distance estimation patterns
data-whitening.md — Whitening on/off comparison and internals
Parameters (bleWaveformGenerator)
| Param | Default | Range |
|---|---|---|
Mode | "LE1M" | LE1M, LE2M, LE500K, LE125K |
ChannelIndex | 37 | 0-39 |
SamplesPerSymbol | 8 | >=1 (use >=4 for plots) |
WhitenStatus | "On" | On, Off |
DFPacketType | "Disabled" | Disabled, ConnectionCTE, ConnectionlessCTE |
AccessAddress | adv default | 32-bit binary col vector |
ModulationIndex | 0.5 | [0.45, 0.55] |
PulseLength | 1 | [1, 4] |
Core Recipe
messageBits = randi([0 1], payloadLenBytes*8, 1);
waveform = bleWaveformGenerator(messageBits, ...
Mode=phyMode, SamplesPerSymbol=sps, ...
ChannelIndex=ch, WhitenStatus="On");
symbolRate = 1e6 + 1e6*(phyMode=="LE2M");
fs = symbolRate * sps;Patterns
All-Mode Comparison
phyModes = ["LE1M","LE2M","LE500K","LE125K"];
sps = 8;
messageBits = randi([0 1], 37*8, 1);
figure; tl = tiledlayout(4,2,TileSpacing="compact",Padding="compact");
title(tl,"BLE - All PHY Modes")
for idx = 1:4
wf = bleWaveformGenerator(messageBits, ...
Mode=phyModes(idx), SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="On");
sr = 1e6 + 1e6*(phyModes(idx)=="LE2M");
fs = sr*sps; t = (0:length(wf)-1)/fs*1e6;
nexttile; plot(t,real(wf),t,imag(wf))
xlabel("Time (\mus)"); ylabel("Amplitude"); title(phyModes(idx)+" - IQ")
legend("I","Q"); grid on; xlim([0 min(80,t(end))])
nexttile; N=length(wf); f=(-N/2:N/2-1)*(fs/N)/1e6;
plot(f, 20*log10(abs(fftshift(fft(wf)))/N+eps))
xlabel("Frequency (MHz)"); ylabel("dB"); title(phyModes(idx)+" - Spectrum")
grid on; xlim([-3 3]); ylim([-80 0])
endMulti-Packet Burst (T_IFS = 150 us)
sps = 8; fs = 1e6*sps;
messageBits = randi([0 1], 37*8, 1);
ifsGap = complex(zeros(round(150e-6*fs), 1));
burst = complex(zeros(0,1));
for pkt = 1:3
wf = bleWaveformGenerator(messageBits, Mode="LE1M", SamplesPerSymbol=sps, ChannelIndex=37);
burst = [burst; wf; ifsGap]; %#ok<AGROW>
endRound-Trip Decode
messageBits = randi([0 1], 37*8, 1); sps = 8;
wf = bleWaveformGenerator(messageBits, Mode="LE1M", SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="On");
rxBits = bleIdealReceiver(wf, Mode="LE1M", SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="On");
assert(isequal(rxBits, messageBits))Data Channel + Custom Access Address
accessAddr = randi([0 1], 32, 1);
wf = bleWaveformGenerator(randi([0 1],27*8,1), ...
Mode="LE2M", SamplesPerSymbol=8, ChannelIndex=9, ...
AccessAddress=accessAddr, WhitenStatus="On");
fs = 2e6 * 8;CTE Generation
messageBits = randi([0 1], 20*8, 1); sps = 8; fs = 1e6*sps;
wf_noCTE = bleWaveformGenerator(messageBits, Mode="LE1M", ...
SamplesPerSymbol=sps, ChannelIndex=10, WhitenStatus="On");
wf_conn = bleWaveformGenerator(messageBits, Mode="LE1M", ...
SamplesPerSymbol=sps, ChannelIndex=10, WhitenStatus="On", DFPacketType="ConnectionCTE");
wf_cless = bleWaveformGenerator(messageBits, Mode="LE1M", ...
SamplesPerSymbol=sps, ChannelIndex=10, WhitenStatus="On", DFPacketType="ConnectionlessCTE");
% CTE appends unmodulated constant tone for antenna switching (typ. 72-216 us)
cteDelta_conn_us = (length(wf_conn) - length(wf_noCTE)) / fs * 1e6;
cteDelta_cless_us = (length(wf_cless) - length(wf_noCTE)) / fs * 1e6;CTE Full Pipeline (Tx → Rx → Angle)
pduHex = '02049B03270102030405'; % 10-byte PDU (>=6 bytes needed for >=11 IQ samples)
pdu = int2bit(hex2dec(reshape(pduHex, 2, [])'), 8, false);
pdu = pdu(:);
cfgCRC = crcConfig(Polynomial="z^24+z^10+z^9+z^6+z^4+z^3+z+1", ...
InitialConditions=int2bit(hex2dec('555551'),24), DirectMethod=true);
pduCRC = crcGenerate(pdu, cfgCRC);
txWf = bleWaveformGenerator(pduCRC, ChannelIndex=36, DFPacketType="ConnectionlessCTE");
[~, ~, iqSamples] = bleIdealReceiver(txWf, ChannelIndex=36, ...
DFPacketType="ConnectionlessCTE", SlotDuration=2);
cfgAngle = bleAngleEstimateConfig;
cfgAngle.ArraySize = 4; cfgAngle.SlotDuration = 2; cfgAngle.SwitchingPattern = [1 2 3 4];
angle = bleAngleEstimate(iqSamples, cfgAngle);Alternative (R2022a+): iqSamples = bleCTEIQSample(cteSamples, Mode="LE1M", SlotDuration=2);
BER Simulation
messageBits = randi([0 1], 100*8, 1); sps = 8; phyMode = "LE1M";
snrValues = 0:4:20; berResults = zeros(size(snrValues));
for idx = 1:length(snrValues)
wf = bleWaveformGenerator(messageBits, Mode=phyMode, SamplesPerSymbol=sps, ChannelIndex=5, WhitenStatus="On");
sigPower = mean(abs(wf).^2);
rxWf = awgn(wf, snrValues(idx), 10*log10(sigPower));
rxBits = bleIdealReceiver(rxWf, Mode=phyMode, SamplesPerSymbol=sps, ChannelIndex=5, WhitenStatus="On");
n = min(length(messageBits), length(rxBits));
berResults(idx) = sum(messageBits(1:n) ~= double(rxBits(1:n))) / n;
end
semilogy(snrValues, berResults, "-o"); xlabel("SNR (dB)"); ylabel("BER"); grid onbleIdealReceiver returns int8 — cast with double(). For Eb/No conversion: snr = convertSNR(EbNo,"ebno","snr",SamplesPerSymbol=sps).
RF-PHY Test Waveform
cfg = bluetoothTestWaveformConfig;
cfg.Mode = "LE1M"; cfg.PayloadLength = 37;
cfg.PacketType = "Disabled"; cfg.ModulationIndex = 0.5;
testWf = bluetoothTestWaveform(cfg);
rfCfg = bluetoothRFPHYTestConfig;
rfCfg.Test = "Output power"; rfCfg.Mode = "LE1M";
rfCfg.PayloadLength = 37; rfCfg.OutputPower = 0; rfCfg.CenterFrequency = "Mid";WLAN Coexistence
sps = 8; fs = 1e6*sps;
bleWf = bleWaveformGenerator(randi([0 1],37*8,1), Mode="LE1M", SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="On");
t = (0:length(bleWf)-1)'/fs;
wlanInterferer = 0.1*complex(randn(length(bleWf),1),randn(length(bleWf),1)) .* exp(1j*2*pi*3e6*t);
combined = bleWf + wlanInterferer;
CIR_dB = 10*log10(mean(abs(bleWf).^2) / mean(abs(wlanInterferer).^2));TX Measurements (Power, OBW, PAPR)
sps = 8; wf = bleWaveformGenerator(randi([0 1],255*8,1), Mode="LE1M", ...
SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="On", ModulationIndex=0.5);
fs = 1e6*sps; N = length(wf);
avgPower_dBm = 10*log10(mean(abs(wf).^2)) + 30;
spec = abs(fftshift(fft(wf))).^2; cumP = cumsum(spec)/sum(spec);
f = (-N/2:N/2-1)*(fs/N);
occBW_MHz = (f(find(cumP>=0.995,1)) - f(find(cumP>=0.005,1))) / 1e6;
papr_dB = 10*log10(max(abs(wf).^2) / mean(abs(wf).^2));Whitening Comparison
bits = randi([0 1], 37*8, 1); sps = 8;
wfOn = bleWaveformGenerator(bits, Mode="LE1M", SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="On");
wfOff = bleWaveformGenerator(bits, Mode="LE1M", SamplesPerSymbol=sps, ChannelIndex=37, WhitenStatus="Off");Advertising PDU (ADV_IND)
cfgAdv = bleLLAdvertisingChannelPDUConfig;
cfgAdv.PDUType = "Advertising indication";
cfgAdv.AdvertiserAddress = "A1B2C3D4E5F6";
cfgAdv.AdvertiserAddressType = "Random";
cfgAdv.AdvertisingData = "0201060709546573744245020A00";
pduBits = bleLLAdvertisingChannelPDU(cfgAdv);
wf = bleWaveformGenerator(pduBits, Mode="LE1M", SamplesPerSymbol=8, ChannelIndex=37);PDUType values: "Advertising indication", "Scan request", "Scan response", "Connection indication", "Advertising direct indication", "Advertising non connectable indication".
Addresses: 12-char hex string (no colons). AdvertisingData: hex string (length-type-value AD structs).
Data Channel PDU
cfgData = bleLLDataChannelPDUConfig;
cfgData.LLID = "Data (start fragment/complete)";
cfgData.SequenceNumber = 1;
cfgData.NESN = 0;
cfgData.MoreData = false;
payload = dec2hex(randi([0 255], 50, 1))'; % 50-byte hex payload
payload = reshape(payload', 1, []);
pduBits = bleLLDataChannelPDU(cfgData, payload);
wf = bleWaveformGenerator(pduBits, Mode="LE2M", SamplesPerSymbol=8, ChannelIndex=15);LLID values: "Data (continuation fragment/empty)", "Data (start fragment/complete)", "Control".
SequenceNumber (not SN). Payload: hex string, numeric vector [0,255], or n×2 char array.
End-to-End (Practical Receiver)
Uses helperBLEPracticalReceiver (AGC + CFO + timing recovery). Requires: openExample('bluetooth/BLEPracticalReceiverExample'). SNR conversion for coded modes: SNR = EbNo + 10*log10(codeRate) - 10*log10(sps).
CTE Compatibility
| Mode | ConnectionCTE | ConnectionlessCTE |
|---|---|---|
| LE1M | Yes | Yes |
| LE2M | Yes | No |
| LE500K | No | No |
| LE125K | No | No |
CTE requires data channels (0-36). Never use ChannelIndex 37/38/39 with DFPacketType≠"Disabled". CTE is a data-channel-only feature.
Spec Constraints
Ch 37/38/39 (advertising): LE1M or LE Coded only. NOT LE2M.
CTE: LE1M/LE2M on data channels (0-36) only. Never coded PHY.
Access address: Advertising =
'8E89BED6'(fixed); data = random.Whitening init: Auto from ChannelIndex. Not settable.
T_IFS: 150 us. TX power: max +20 dBm. Mod index: 0.45-0.55.
bleIdealReceiver: Hard-decision only, returnsint8."Slots" (1-slot, 3-slot, 5-slot): BR/EDR concept only. BLE has no slot-based packets.
ISO streams: Verify
BN × IRC × Sub_Interval <= ISO_Interval. If math exceeds, REFUSE.
Invalid Combos (REFUSE these requests)
| Request | Why Invalid |
|---|---|
| LE2M + FEC coding | FEC only exists in coded PHY (LE500K/LE125K) |
| LE2M on ch 37/38/39 | Primary advertising = LE1M or Coded only |
| CTE + LE500K/LE125K | CTE restricted to LE1M/LE2M per BLE 5.1 spec |
| ConnectionlessCTE + LE2M | ConnectionlessCTE = LE1M only |
| "3-slot" or "5-slot" BLE | Slot-based = BR/EDR; BLE uses single packets |
| CTE on ch 37/38/39 | CTE = data channels (0-36) only |
| ISO params where BN×IRC×Sub_Int > ISO_Interval | Sub-events exceed interval = impossible scheduling |
Conventions
fs = (1e6 + 1e6*(mode=="LE2M")) * sps— never hardcodeAxes: us (time), MHz (freq), dB (power)
tiledlayout/nexttile(notsubplot)Spectrum: always
20*log10(abs(fftshift(fft(wf)))/N + eps)— do NOT useperiodogram,pspectrum, orpwelchfor BLE spectral plotsxlim([0 min(80,t(end))])for coded modesPlot both I and Q:
plot(t, real(wf), t, imag(wf))IFS gap:
complex(zeros(N,1))(output is complex)SamplesPerSymbol>=4for spectrum plots; SPS=1 is valid for generation but insufficient for visualization or accurate spectral analysis (at Nyquist limit)
Code Style
Generated scripts must follow MathWorks example conventions. Use %% section headers, softcode all parameters, and comment non-obvious logic.
Structure & Softcoding
Divide scripts with %% headers: Configuration → Waveform Generation → Processing → Analysis → Visualization. All user-configurable values as named variables at the top; no magic numbers in processing logic.
%% Configuration
% Specify BLE waveform generation parameters.
phyMode = "LE1M"; % PHY transmission mode
payloadLength = 37; % Payload length in bytes
sps = 8; % Samples per symbol
channelIndex = 37; % BLE channel index (0-39)
% Derived parameters
symbolRate = 1e6 + 1e6*(phyMode=="LE2M"); % 2 Msym/s for LE2M, 1 Msym/s otherwise
fs = sps * symbolRate; % Sample rate in Hz
numBits = payloadLength * 8; % Payload length in bits
%% Waveform Generation
% Generate BLE waveform from random payload bits.
messageBits = randi([0 1], numBits, 1);
waveform = bleWaveformGenerator(messageBits, ...
Mode=phyMode, SamplesPerSymbol=sps, ChannelIndex=channelIndex);Comments
Inline (right-aligned): units, range, or brief purpose —
% Eb/No in dBBlock (above 2-5 lines): intent or why —
% IFS gap must be complex (bleWaveformGenerator output is complex)Constraints: spec reference —
% LE2M uses 2 Msym/s (only mode with 2x symbol rate)Do NOT comment self-evident lines, every line mechanically, or closing
endstatements
Naming
camelCase:
messageBits,txWaveform,symbolRate,channelIndexDescriptive loop counters:
countMode,pktIdx(noti,j)Named constants:
bitsPerByte = 8,tIFS = 150e-6Multi-init:
[numErrors, perCount] = deal(0, 0)
Gotchas
| Mistake | Fix |
|---|---|
bleWaveformConfig(...) | Does not exist. Use bleWaveformGenerator(bits, NV...) directly |
bluetoothWaveformGenerator for BLE | BR/EDR only. Use bleWaveformGenerator |
comm.BLEReceiver | Does not exist. Use bleIdealReceiver |
symbolRate=1e6 for LE2M | LE2M = 2e6 |
'PHYMode' as param name | Use 'Mode' |
'LECODED' as mode | Use "LE500K" or "LE125K" |
| Config object as 1st arg | Must be binary col vector randi([0 1],N,1) |
Empty [] bits | Minimum 1 byte |
Real zeros() for IFS | Use complex(zeros(N,1)) |
| CTE + coded modes | CTE only on LE1M/LE2M |
ConnectionlessCTE + LE2M | LE1M only |
| LE2M on ch 37/38/39 | Spec violation. Use LE1M or Coded |
CTELength/CTEType as NV args | Not valid. Use DFPacketType |
bleAngleEstimate(wf, NV...) | Use bleAngleEstimate(iqSamples, bleAngleEstimateConfig) |
bleWaveformGenerator for RF-PHY | Use bluetoothTestWaveformConfig + bluetoothTestWaveform |
| AWGN without oversampling correction | Use convertSNR(EbNo,"ebno","snr",SamplesPerSymbol=sps); pass explicit power to awgn (never use "measured") |
bleIdealReceiver with impairments | Use helperBLEPracticalReceiver |
| Eb/No for coded modes without code rate | SNR = EbNo + 10*log10(codeRate) - 10*log10(sps) |
| SPS=1 without warning | SPS=1 is at Nyquist limit — warn user: no spectral analysis, marginal decode performance |
Timing ppm offset without resample | Apply clock drift via resample(wf, 1e6+ppm, 1e6) or fractional delay filter |
| Conformance Df1/Df2 without PRBS9 | Use comm.PNSequence (z^9+z^5+1) for TP/TRM/CA/BV-05-C; separate stable-bit (Df1) from alternating-bit (Df2) patterns |
periodogram/pwelch for BLE spectrum | Use manual fftshift(fft(wf)) — skill convention |
SN as property name | Use SequenceNumber on bleLLDataChannelPDUConfig |
Address with colons "A1:B2:..." | Use 12-char hex string without colons: "A1B2C3D4E5F6" |
PDUType="ADV_IND" | Use full string: "Advertising indication" |
| Binary vector as AdvertisingData | Use hex string: "0201060709..." (length-type-value) |
Copyright 2026 The MathWorks, Inc.
Files
- ATTRIBUTION.mdAdded by AutoGineer1.1 KiB
- LICENSELicence file added by AutoGineer1.4 KiB
- SKILL.md17.9 KiB
- manifest.yaml432 B
- references/cte-direction-finding.md1.6 KiB
- references/data-whitening.md1.2 KiB
- references/direction-finding.md3.3 KiB
- references/functionalAPI.md17.6 KiB
- references/phy-modes-and-timing.md2.9 KiB
- references/practical-receiver-simulation.md13.4 KiB
- references/rfphy-compliance-testing.md1.7 KiB
- references/rssi-localization.md1.5 KiB
- references/transmitter-measurements.md1.2 KiB
- references/wlan-coexistence.md1.3 KiB
references/functionalAPI.md
Bluetooth Toolbox — Functional API Reference
Verified against official MathWorks documentation (2026-05-21). Use this file to avoid re-fetching web docs for Bluetooth Toolbox functions.
1. bleWaveformGenerator (R2022a)
Purpose: Generate BLE PHY waveform from message bits.
Syntax
waveform = bleWaveformGenerator(message)
waveform = bleWaveformGenerator(message, Name=Value)Input: message
Binary-valued column vector (PDU + CRC data)
Maximum length: 2088 bits
Data types:
double|single|int8|logical
Name-Value Arguments
| Parameter | Default | Valid Values | Notes |
|---|---|---|---|
Mode | "LE1M" | "LE1M", "LE2M", "LE500K", "LE125K" | PHY mode |
ChannelIndex | 37 | 0-39 | Used by whitening block |
SamplesPerSymbol | 8 | Positive integer | GFSK modulation |
WhitenStatus | "On" | "On", "Off" | Data whitening |
DFPacketType | "Disabled" | "Disabled", "ConnectionlessCTE", "ConnectionCTE" | CTE enable |
AccessAddress | Advertising default | 32-bit column vector | Override access addr |
ModulationIndex | 0.5 | [0.45, 0.55] | GFSK mod index |
PulseLength | 1 | [1, 4] symbol intervals | Frequency pulse shape |
OutputDataType | (inferred) | "single", "double" | Output precision |
Output: waveform
Complex column vector (Ns-by-1)
LE1M/LE2M: includes 40 extra bits (access address + preamble)
Data types:
double|single
Critical Notes
No config object.
bleWaveformConfigdoes NOT exist.CTE is NOT configured via CTELength/CTEType NV args. CTE parameters are encoded in the PDU bits. Only
DFPacketTypeenables CTE processing.First arg must be binary column vector, not struct/object.
Symbol rate: LE2M = 2 MHz, all others = 1 MHz.
2. bleIdealReceiver (R2022a)
Purpose: Decode BLE PHY waveform. Returns bits, access address, and optionally CTE IQ samples.
Syntax
[bits, accessAddr] = bleIdealReceiver(waveform)
[bits, accessAddr] = bleIdealReceiver(waveform, Name=Value)
[bits, accessAddr, IQsamples] = bleIdealReceiver(___)Input: waveform
Complex column vector (Ns-by-1)
Minimum Ns by mode:
| Mode | Min Ns | Must be multiple of |
|---|---|---|
| LE1M | 40×sps | sps |
| LE2M | 48×sps | sps |
| LE500K | 376×sps | 2×sps |
| LE125K | 376×sps | 8×sps |
Name-Value Arguments
| Parameter | Default | Valid Values | Notes |
|---|---|---|---|
Mode | "LE1M" | "LE1M", "LE2M", "LE500K", "LE125K" | Must match generator |
ChannelIndex | 37 | 0-39 | Must match generator |
SamplesPerSymbol | 8 | Positive integer | Must match generator |
WhitenStatus | "On" | "On", "Off" | Must match generator |
DFPacketType | "Disabled" | "Disabled", "ConnectionlessCTE", "ConnectionCTE" | Enables IQ output |
SlotDuration | 2 | 1, 2 (microseconds) | CTE slot duration |
ModulationIndex | 0.5 | [0.45, 0.55] | GFSK trellis params |
PulseLength | 1 | [1, 4] | Frequency pulse shape |
NoiseVariance | 1 | Positive scalar (linear) | Input noise variance |
Outputs
| Output | Description | Type |
|---|---|---|
bits | Recovered payload bits (max 260 bytes) | int8 column vector |
accessAddr | 32-bit access address | int8 column vector |
IQsamples | CTE IQ samples (only when DFPacketType != "Disabled") | Complex column vector |
Critical Notes
3rd output (IQsamples) only returned when
DFPacketTypeis set to CTE mode.All NV args (Mode, ChannelIndex, SamplesPerSymbol, WhitenStatus) must match the generator settings.
Performs ideal (noiseless reference) demodulation — no receiver impairments modeled.
3. bleCTEIQSample (R2022a)
Purpose: Extract IQ samples from CTE portion of a BLE waveform by performing IQ sampling at reference period and each sample slot.
Syntax
iqSamples = bleCTEIQSample(cteSamples)
iqSamples = bleCTEIQSample(cteSamples, Name=Value)Input: cteSamples
Complex column vector (CTE portion only, not full waveform)
Size constraints:
| Mode | Ns range | Must be multiple of |
|---|---|---|
| LE1M | [16×sps, 160×sps] | 8×sps |
| LE2M | [32×sps, 320×sps] | 16×sps |
Name-Value Arguments
| Parameter | Default | Valid Values | Notes |
|---|---|---|---|
Mode | "LE1M" | "LE1M", "LE2M" | Only uncoded modes |
SamplesPerSymbol | 8 | Positive integer | — |
SlotDuration | 2 | 1, 2 (microseconds) | Switch/sample slot |
SampleOffset | 4 | Depends on mode (see below) | Sampling point offset |
SampleOffset range:
| Mode | Range |
|---|---|
| LE1M | [sps/8, 7×(sps/8)] |
| LE2M | [sps/4, 7×(sps/4)] |
Output: iqSamples
Complex column vector
Corresponds to 8 us reference period and SlotDuration
Critical Notes
Input is the CTE portion only — not the full BLE waveform.
Only LE1M and LE2M (no coded modes).
Alternative to using
bleIdealReceiver3rd output.
4. bleAngleEstimate (R2020b)
Purpose: Estimate AoA or AoD from IQ samples.
Syntax
angle = bleAngleEstimate(IQsamples, cfgAngle)No name-value arguments. Only two positional inputs.
Input: IQsamples
Complex column vector
Corresponds to 8 us reference period and slot duration
Obtained from
bleIdealReceiver(3rd output) orbleCTEIQSample
Input: cfgAngle
bleAngleEstimateConfigobject (see below)
Output: angle
Scalar (azimuth only, when elevation = 0) OR
Two-element row vector
[azimuth, elevation](when custom array enabled)
Critical Notes
Does NOT take name-value args. Does NOT take a waveform directly.
Input must be pre-extracted IQ samples, not raw waveform.
Since R2020b (not R2021a).
5. bleAngleEstimateConfig (R2020b)
Purpose: Configuration object for bleAngleEstimate.
Syntax
cfgAngle = bleAngleEstimateConfig
cfgAngle = bleAngleEstimateConfig(Name=Value)Properties
| Property | Default | Valid Values | Description |
|---|---|---|---|
ArraySize | — | Integer >=2 (ULA) or [M,N] (URA) | Antenna array size |
ElementSpacing | 0.5 | Positive scalar <=0.5 | Normalized spacing (wavelengths) |
SlotDuration | 2 | 1, 2 | Switch/sample slot (us) |
SwitchingPattern | — | Integer vector | Antenna switching order |
EnableCustomArray | false | true/false | Use custom element positions |
ElementPosition | — | 3×N matrix | Normalized positions (custom only) |
6. bluetoothWhiten (System Object, R2022b)
Purpose: Whiten or dewhiten data bits using LFSR (x⁷+x⁴+1).
Creation
whiten = bluetoothWhiten
whiten = bluetoothWhiten(Name=Value)Properties
| Property | Default | Valid Values | Tunable |
|---|---|---|---|
InitialConditionsSource | "Property" | "Property", "Input port" | No |
InitialConditions | [1;1;1;1;1;1;1] | 7-bit binary column vector (>=1 nonzero) | No |
Calling
y = whiten(x) % uses InitialConditions property
y = whiten(x, initCondition) % uses input port (requires InitialConditionsSource="Input port")Notes
Same operation whitens and dewhitens (apply twice = original)
Channel-index-based init:
initCond = [1; int2bit(channelIndex, 6)]bleWaveformGenerator handles whitening internally when
WhitenStatus="On"
7. bluetoothRFPHYTestConfig (R2022a)
Purpose: Configure BLE RF-PHY transmitter/receiver test parameters per RF-PHY.TS.p15.
Syntax
cfgRFPHYTest = bluetoothRFPHYTestConfig
cfgRFPHYTest = bluetoothRFPHYTestConfig(Name=Value)Key Properties
| Property | Default | Valid Values |
|---|---|---|
Test | "Output Power" | 13 test types (see below) |
Mode | "LE1M" | "LE1M", "LE2M", "LE125K", "LE500K" |
PayloadLength | 37 | [31, 255] bytes |
PacketType | "Disabled" | "Disabled", "ConnectionCTE" |
CTELength | 2 | [2, 20] (×8 us) |
CTEType | [0;0] | [0;0]=AoA, [0;1]=AoD 2us, [1;0]=AoD 1us |
SamplesPerSymbol | 8 | Positive integer |
ArraySize | 4 | Integer >=2 |
ElementSpacing | 0.5 | <=0.5 |
ModulationIndex | 0.5 | [0.45, 0.55] |
NumPackets | 1 | Positive integer |
Test types: "Output Power", "Inband emissions", "Modulation characteristics", "Carrier frequency offset and drift", "Tx power stability", "C/I", "Blocking", "Intermodulation", "Receiver sensitivity", "Maximum input signal level", "PER report integrity", "IQ samples coherency", "IQ samples dynamic range"
Notes
This config goes to
bluetoothTestWaveform(generation) andbluetoothTestWaveformValidate(validation).CTELength/CTEType properties only available when PacketType="ConnectionCTE" and Mode is LE1M/LE2M.
8. bluetoothTestWaveformConfig (R2022a)
Purpose: Configure bluetoothTestWaveform for generating BR/EDR or LE test waveforms.
Syntax
cfgTestWaveform = bluetoothTestWaveformConfig
cfgTestWaveform = bluetoothTestWaveformConfig(Name=Value)Key Properties
| Property | Default | Valid Values | Notes |
|---|---|---|---|
Mode | "LE1M" | "LE1M", "LE2M", "LE125K", "LE500K", "BR", "EDR2M", "EDR3M" | All BLE + BR/EDR |
PayloadType | 0 | [0, 7] | Test payload pattern |
PayloadLength | 255 | [0, 255] bytes | LE modes only |
PacketType | "Disabled" | Mode-dependent (see below) | Test packet type |
SamplesPerSymbol | 8 | Positive integer | — |
WhitenStatus | "On" | "On", "Off" | — |
WhitenInitialization | [1;1;1;1;1;1;1] | 7-bit binary vector | When WhitenStatus="On" |
ModulationIndex | 0.5 | [0.45,0.55] LE, [0.28,0.35] BR/EDR | — |
PulseLength | 1 | [1, 4] | LE modes only (R2023a+) |
CTELength | 2 | [2, 20] | LE1M/LE2M + ConnectionCTE |
CTEType | [0;0] | [0;0], [0;1], [1;0] | LE1M/LE2M + ConnectionCTE |
PacketType by Mode:
LE1M/LE2M:
"ConnectionCTE","Disabled"LE125K/LE500K:
"Disabled"onlyBR:
"DH1","DH3","DH5","DM1","DM3","DM5"EDR2M:
"2-DH1","2-DH3","2-DH5","2-EV3","2-EV5"EDR3M:
"3-DH1","3-DH3","3-DH5","3-EV3","3-EV5"
9. bluetoothTestWaveformValidate (R2024a)
Purpose: Validate BLE RF-PHY test waveform against test procedures.
Syntax (multiple forms based on test type)
crcError = bluetoothTestWaveformValidate(waveform, cfgRFPHYTest)
[waveformOut, avgFreqDev, avgCenterFreq, maxFreqDev] = bluetoothTestWaveformValidate(...)
[waveformOut, initFreqOffset, carrierFreqDrift] = bluetoothTestWaveformValidate(...)
[relativePhase, sumRelativePhase, angleRelativePhase, ...] = bluetoothTestWaveformValidate(...)
[meanAmpRefAntennas, meanAmpNonRefAntennas] = bluetoothTestWaveformValidate(...)Inputs
| Argument | Type | Description |
|---|---|---|
waveform | Complex Ns-by-Np | Test waveform |
cfgRFPHYTest | bluetoothRFPHYTestConfig | Test configuration |
Minimum Ns by Mode
| Mode | Min Ns | Multiple of |
|---|---|---|
| LE1M | 248×sps | sps |
| LE2M | 256×sps | sps |
| LE500K | 1054×sps | 2×sps |
| LE125K | 3088×sps | 8×sps |
Notes
Output structure depends on which test is configured in cfgRFPHYTest.
Validates: blocking, C/I, carrier freq offset/drift, intermod, IQ coherency, IQ dynamic range, modulation characteristics, PER integrity.
10. bluetoothPathLoss (R2022b)
Purpose: Estimate path loss between Bluetooth BR/EDR or LE devices.
Syntax
pathLoss = bluetoothPathLoss(distance, cfgPathLoss)Inputs
| Argument | Type | Description |
|---|---|---|
distance | Nonneg scalar or row vector (meters) | Device separation |
cfgPathLoss | bluetoothPathLossConfig object | Path loss config |
Output
| Argument | Type | Description |
|---|---|---|
pathLoss | Scalar or row vector (dB) | Estimated loss |
11. bluetoothPathLossConfig (R2022b)
Purpose: Configure path loss model for bluetoothPathLoss.
Syntax
cfgPathLoss = bluetoothPathLossConfig
cfgPathLoss = bluetoothPathLossConfig(Name=Value)Properties
| Property | Default | Valid Values | Notes |
|---|---|---|---|
Environment | "Outdoor" | "Home", "Industrial", "Office", "Outdoor" | Selects model |
TransmitterAntennaGain | 0 | [-10, 10] dBi | — |
ReceiverAntennaGain | 0 | [-10, 10] dBi | — |
TransmitterCableLoss | 0 | Nonneg (dB) | — |
ReceiverCableLoss | 0 | Nonneg (dB) | — |
TransmitterAntennaHeight | 1 | Positive (meters) | Outdoor only |
ReceiverAntennaHeight | 1 | Positive (meters) | Outdoor only |
PathLossExponent | 2.2 | Positive scalar | Industrial only |
StandardDeviation | 2.667 | Nonneg (dB) | Industrial/Outdoor |
RandomStream | "Global stream" | "Global stream", "mt19937ar with seed" | — |
Seed | 73 | Nonneg scalar | When mt19937ar |
PathLossModel (read-only, derived from Environment):
Outdoor → TwoRayGroundReflection
Industrial → LogNormalShadowing
Home/Office → NISTPAP02Task6
12. bleCSWaveform (R2024b)
Purpose: Generate BLE Channel Sounding PHY waveform.
Syntax
csPHYWaveform = bleCSWaveform(cfgChannelSounding)
[csPHYWaveform, accessAddress] = bleCSWaveform(cfgChannelSounding)Input: cfgChannelSounding
A bleCSConfig object with properties:
Mode:"LE1M","LE2M","LE2M 2BT"(2BT since R2026a)SamplesPerSymbol: positive integerDeviceRole:"Initiator","Reflector"StepMode: 0, 1, 2, 3ToneDuration: 80 (StepMode 0) or 10/20/40 (StepMode 2,3) microsecondsSequenceType:"Sounding Sequence","Random Sequence"SequenceLength: 32/96 (sounding) or 32/64/96/128 (random) bits
Outputs
| Output | Type | Description |
|---|---|---|
csPHYWaveform | Complex column vector | CS waveform |
accessAddress | int8 32-bit vector | CS DRBG access address |
Notes
Completely separate from
bleWaveformGenerator— different API, different config.Guard duration fixed at 10 us.
LE2M uses 2x multiplicative factor for sample counts.
Function Availability Timeline
| Release | Functions Added |
|---|---|
| R2022a | bleWaveformGenerator, bleIdealReceiver |
| R2020b | bleAngleEstimate, bleAngleEstimateConfig |
| R2022a | bleCTEIQSample, bluetoothRFPHYTestConfig, bluetoothTestWaveformConfig, bluetoothTestWaveform |
| R2022b | bluetoothWhiten, bluetoothPathLoss, bluetoothPathLossConfig |
| R2024a | bluetoothTestWaveformValidate |
| R2024b | bleCSWaveform, bleCSConfig |
| R2026a | bleCSConfig adds "LE2M 2BT" mode |
CTE Workflow Summary (Verified)
1. Build PDU bits with CTE info encoded in header
2. Append CRC: crcGenerate(pdu, cfgCRC)
3. Generate: bleWaveformGenerator(pduCRC, DFPacketType="ConnectionlessCTE", ChannelIndex=N)
4. Extract IQ:
Option A: [bits, addr, iq] = bleIdealReceiver(waveform, DFPacketType="ConnectionlessCTE", SlotDuration=2)
Option B: iq = bleCTEIQSample(cteSamples, Mode="LE1M", SlotDuration=2)
5. Estimate: angle = bleAngleEstimate(iq, bleAngleEstimateConfig(...))NOT valid:
bleWaveformGenerator(..., CTELength=16, CTEType="AoA")— these are NOT NV argsbleAngleEstimate(waveform, Mode=..., CTELength=...)— takes (iqSamples, configObj)
Practical Receiver Helpers (Example-Based, R2022a)
These are NOT built-in functions — they ship as example helpers. Access via:
openExample('bluetooth/BLEPHYWithRFImpairmentsAndCorrectionsExample')helperBLEImpairmentsInit
Purpose: Initialize RF impairment parameters struct.
initImp = helperBLEImpairmentsInit(phyMode, sps)Output struct fields:
pfo— Phase/frequency offset object (set.FrequencyOffset,.PhaseOffset)vdelay— Variable delay vector (timing drift)dc— DC offset percentage
helperBLEImpairmentsAddition
Purpose: Apply all RF impairments to a BLE waveform.
txImpairedWfm = helperBLEImpairmentsAddition(txWaveform, initImp)Applies: frequency offset → phase offset → timing drift → DC offset.
helperBLEPracticalReceiver
Purpose: Full practical receiver with impairment corrections.
[rxBits, accessAddress] = helperBLEPracticalReceiver(rxWaveform, rxCfg)rxCfg struct fields:
| Field | Value |
|---|---|
Mode | PHY mode string |
SamplesPerSymbol | sps |
DFPacketType | "Disabled" |
ChannelIndex | 0-39 |
AccessAddress | 32-bit binary vector |
CoarseFreqCompensator | comm.CoarseFrequencyCompensator object |
PreambleDetector | comm.PreambleDetector object |
RX pipeline: AGC → DC removal → coarse CFO → matched filter → preamble detection → timing correction → demod → de-whiten.
helperBLEReferenceResults
Purpose: Compute Bluetooth spec reference BER/PER values.
[refBER, refPER, refEbNo] = helperBLEReferenceResults(phyMode, payloadLen)Eb/No to SNR Conversion
% Uncoded (LE1M, LE2M):
snr = EbNo - 10*log10(sps);
% Coded (LE500K, rate=1/2):
snr = EbNo + 10*log10(1/2) - 10*log10(sps);
% Coded (LE125K, rate=1/8):
snr = EbNo + 10*log10(1/8) - 10*log10(sps);Copyright 2026 The MathWorks, Inc. Last verified: 2026-05-22 from in.mathworks.com/help/bluetooth/ref/
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
The author says: >=R2022a
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- MathWorks
- Publisher
- MathWorks (Official)
- Source
- matlab/matlab-agentic-toolkit · skills-catalog/wireless-communications/matlab-generate-ble-waveform · commit 2a7f215
- Licence
- BSD 2-Clause License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MathWorks.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download matlab-generate-ble-waveform.zip