NB-IoT Signalling


Narrowband Internet of Things (NB-IoT) is the 3GPP alternative to other Low Power Wide Area Network (LPWAN) technologies, such as SigFox and LoRa. Technically it uses similar ideas and reuses some of the components of LTE. But the bandwidth is significantly reduced to a single PRB (180 kHz) in order to achieve the low-complexity, low-cost, long battery life requirements. It was first standardized in Release 13.

This application note shows how to spot and decode commercial NB-IoT transmissions in the first part. The second part shows how to transmit and receive your own NB-IoT downlink signal.


The NB-IoT examples require a radio that can sample at 1.92 Msps. Since the bandwidth of an NB-IoT carrier is very small, even very cheaply available devices are sufficient to receive and decode the signal. For example, popular RTL-SDR USB dongles available for around 15-20 Euro are fine for decoding the signal.

The eNB transmitter example requires a radio with transmitting capabilities. For example, an Ettus B200mini can be used as the eNB transmitter and an RTL-SDR as UE receiver. In principle, any device supported by either UHD or SoapySDR should work.

The following application also supports srsGUI for real time visualization of data.

All of the examples used here can be found in the following directory: `./srsRAN/build/lib/examples`

Spotting local NB-IoT deployments

Cell search architecture block diagram

Basic system architecture required to perform a cell search and decode transmissions.

Most NB-IoT deployments can be found in the sub-GHz bands. In Europe especially band 20 (Downlink 791-821 MHz). To run a NB-IoT cell search on band 20 one can simply run:

$ ./lib/examples/cell_search_nbiot -b 20
Opening RF device...
[INFO] [UHD] linux; GNU C++ version 8.3.0; Boost_106700; UHD_3.13.1.0-3build1
[INFO] [LOGGING] Fastpath logging disabled at runtime.
Opening USRP channels=1, args: type=b200,master_clock_rate=23.04e6
[INFO] [B200] Detected Device: B200mini
[INFO] [B200] Operating over USB 3.
[INFO] [B200] Initialize CODEC control...
[INFO] [B200] Initialize Radio control...
[INFO] [B200] Performing register loopback test...
[INFO] [B200] Register loopback test passed
[INFO] [B200] Asking for clock rate 23.040000 MHz...
[INFO] [B200] Actually got clock rate 23.040000 MHz.
[  0/299]: EARFCN 6150, 791.00 MHz looking for NPSS.
[  1/299]: EARFCN 6151, 791.10 MHz looking for NPSS.
[  2/299]: EARFCN 6152, 791.20 MHz looking for NPSS.
[105/299]: EARFCN 6253, 801.30 MHz looking for NPSS.
NSSS with peak=95.885849, cell-id: 257, partial SFN: 0
Found CELL ID 257.
[295/299]: EARFCN 6445, 820.50 MHz looking for NPSS.
[296/299]: EARFCN 6446, 820.60 MHz looking for NPSS.
[297/299]: EARFCN 6447, 820.70 MHz looking for NPSS.
[298/299]: EARFCN 6448, 820.80 MHz looking for NPSS.

Found 1 cells
Found CELL 801.3 MHz, EARFCN=6253, PHYID=257, NPSS power=31.0 dBm


In this example, we’ve found a NB-IoT carrier at 801.3 MHz. We can now use the npdsch_ue example (see next section) to decode the transmission.

It’s also possible to just have a look at the spectrum and check for an NB-IoT carrier there. Most of the time the carrier is clearly visible, it’s close to a LTE carrier in most cases and usually even a bit stronger than the LTE signal itself.

The example below, shows a 10 MHz Downlink LTE signal at 806 MHz. One can spot the NB-IoT carrier on the left hand side (the guardband) of the LTE spectrum.


The table below shows some examples of known NB-IoT deployments in Europe.




Frequency (MHz)





















Decoding the NB-IoT transmission

Once we’ve found the downlink frequency of an NB-IoT carrier, we can use the npdsch_ue example to decode the signal. The application should synchronize on the carrier, detect the cell ID and start to decode MIB, SIB and SIB2.

$ ./lib/examples/npdsch_ue -f 801.3e6
Opening RF device...
Soapy has found device #0: driver=rtlsdr, label=Generic RTL2832U OEM :: 00000001, manufacturer=Realtek, product=RTL2838UHIDIR, serial=00000001, tuner=Rafael Micro R820T,
Selecting Soapy device: 0
Set RX freq: 801.300000 MHz
Setting sampling rate 1.92 MHz
NSSS with peak=65.811836, cell-id: 257, partial SFN: 0
*Found n_id_ncell: 257 DetectRatio= 0% PSR=10.57, Power=111.7 dBm
MIB received (CFO:  -2,82 kHz) FrameCnt: 0, State: 10
SIB1 received
SIB2 received
CFO:  -2,76 kHz, RSRP: 28,0 dBm SNR:  5,0 dB, RSRQ: -11,5 dB, NPDCCH detected: 0, NPDSCH-BLER:  0,00% (0 of total 2), NPDSCH-Rate:  0,10

If you’ve compiled srsRAN with GUI support you should see something like this on your screen.


You can stop the UE decoder with Ctrl+C. Upon exit, the application writes a PCAP file of the decoded signal to /tmp/npdsch.pcap. This file can be inspected with Wireshark. The screenshot below shows Wireshark decoding the received signal.


Known issues

  • Cell ID detection isn’t reliable.

    In some cases the cell ID detection using the NSSS signal isn’t working reliably. In case the npdsch_ue application clearly synchronizes to the downlink signal (you see a strong correlation peak in the middle graph in the GUI) but the MIB is never decoded, it is very likely that the cell ID wasn’t detected correctly. In this case, try to restart the application again and see if the cell ID can be detected. If the problem still persists, one can also try to set the cell ID manually with the -l parameter. For this you need to first figure out the correct value, which sometimes can be done by decoding the default LTE carrier with pdsch_ue and use the same cell ID for the NB-IoT carrier.