1132 NB-IoT Lab Simulation
Hands-On ESP32 Simulation of NB-IoT Concepts
1132.1 Learning Objectives
By the end of this lab, you will be able to:
- Understand the NB-IoT attach procedure: Experience cell search, RRC connection, and authentication steps
- Configure PSM timers: Observe T3412 and T3324 timer behavior in simulation
- Compare PSM vs eDRX: See how different power modes affect sleep/wake patterns
- Analyze Coverage Enhancement: Understand how repetitions improve coverage at cost of power
- Calculate battery life: Use simulation data to project real-world battery consumption
1132.2 Lab Overview
This interactive lab provides a hands-on simulation of NB-IoT concepts using an ESP32 microcontroller in Wokwi. While actual NB-IoT communication requires specialized cellular modules and carrier connectivity, this simulation demonstrates the key concepts and procedures that real NB-IoT devices perform.
What You Will Learn:
- Network Attach Procedure: Understand the multi-step process devices use to connect to cellular networks
- PSM (Power Saving Mode): Experience how devices achieve 10+ year battery life through deep sleep states
- eDRX (Extended Discontinuous Reception): Learn the trade-offs between power saving and downlink responsiveness
- Coverage Extension Modes: See how signal repetition enables deep indoor penetration
- Uplink Data Transmission: Observe the overhead involved in sending small IoT payloads
- Network Status Monitoring: Track signal quality, network registration, and connection states
Prerequisites: Basic understanding of C/C++ programming and familiarity with microcontroller concepts.
1132.3 Lab Environment
The simulation below runs on an ESP32 in Wokwiβs browser-based environment. The code simulates NB-IoT modem behavior, including realistic timing, state machines, and power calculations.
- Copy the code from the section below into the Wokwi editor
- Click βStart Simulationβ to run the NB-IoT simulation
- Open the Serial Monitor (115200 baud) to see detailed output
- Observe the state transitions as the simulated device attaches to the network
- Try the challenge exercises to deepen your understanding
1132.4 Complete NB-IoT Simulation Code
Copy this code into the Wokwi editor to run the simulation:
/*
* NB-IoT Fundamentals Lab - ESP32 Simulation
*
* This simulation demonstrates key NB-IoT concepts:
* - Network attach procedure (PLMN search, RRC connection, authentication)
* - Power Saving Mode (PSM) with T3412 and T3324 timers
* - Extended Discontinuous Reception (eDRX) cycles
* - Coverage Enhancement (CE) levels and repetitions
* - Uplink data transmission with control plane optimization
* - Signal quality monitoring (RSRP, RSRQ, SINR)
*
* Educational Purpose: Understanding NB-IoT without actual cellular hardware
*
* Author: IoT Class Lab
* License: MIT
*/
#include <Arduino.h>
// ============================================================================
// NB-IoT Configuration Constants
// ============================================================================
// Network Configuration
#define PLMN_MCC "310" // Mobile Country Code (US)
#define PLMN_MNC "410" // Mobile Network Code (AT&T)
#define BAND_NUMBER 12 // LTE Band 12 (700 MHz) - common for NB-IoT
#define EARFCN 5110 // E-UTRA Absolute Radio Frequency Channel Number
// PSM Timer Configuration (T3412 - TAU timer, T3324 - Active timer)
#define T3412_VALUE_HOURS 24 // TAU (Tracking Area Update) period
#define T3324_VALUE_SECONDS 30 // Active timer before entering PSM
// eDRX Configuration
#define EDRX_CYCLE_SECONDS 20.48 // eDRX cycle (5.12s to 2.91 hours possible)
#define PTW_SECONDS 2.56 // Paging Time Window within eDRX cycle
// Coverage Enhancement Levels
#define INITIAL_CE_LEVEL 0
// Power Consumption Values (typical for NB-IoT modules)
#define POWER_IDLE_MA 0.003 // PSM sleep: 3 uA
#define POWER_EDRX_MA 0.5 // eDRX sleep: 0.5 mA
#define POWER_RX_MA 46 // Receiving: 46 mA
#define POWER_TX_MA 220 // Transmitting (23 dBm): 220 mA
#define POWER_SEARCH_MA 80 // Cell search: 80 mA
// Timing Constants (milliseconds)
#define CELL_SEARCH_TIME_MS 3000
#define RRC_CONNECT_TIME_MS 500
#define AUTHENTICATION_TIME_MS 1000
#define TAU_PROCEDURE_TIME_MS 800
#define DATA_TRANSFER_TIME_MS 200
// ============================================================================
// Enumerations and Type Definitions
// ============================================================================
// NB-IoT Device States (based on 3GPP specifications)
enum NBIoTState {
STATE_POWER_OFF,
STATE_CELL_SEARCH,
STATE_CELL_SELECTION,
STATE_RRC_IDLE,
STATE_RRC_CONNECTING,
STATE_RRC_CONNECTED,
STATE_AUTHENTICATING,
STATE_REGISTERED,
STATE_DATA_TRANSFER,
STATE_PSM,
STATE_EDRX_SLEEP,
STATE_EDRX_PAGING
};
// Coverage Enhancement Levels
enum CELevel {
CE_LEVEL_0 = 0, // Normal coverage (no repetitions)
CE_LEVEL_1 = 1, // Robust (up to 32 repetitions)
CE_LEVEL_2 = 2 // Extreme (up to 128 repetitions)
};
// Power Saving Mode Types
enum PowerMode {
POWER_MODE_CONNECTED,
POWER_MODE_EDRX_ONLY,
POWER_MODE_PSM_ONLY,
POWER_MODE_PSM_EDRX
};
// Network Registration Status
enum RegistrationStatus {
REG_NOT_REGISTERED = 0,
REG_REGISTERED_HOME = 1,
REG_SEARCHING = 2,
REG_DENIED = 3,
REG_UNKNOWN = 4,
REG_REGISTERED_ROAMING = 5
};
// ============================================================================
// Data Structures
// ============================================================================
struct SignalQuality {
int rsrp;
int rsrq;
int sinr;
int cellId;
int earfcn;
};
struct NetworkInfo {
char mcc[4];
char mnc[4];
int band;
int tac;
bool attached;
RegistrationStatus regStatus;
};
struct PowerStats {
float totalEnergyMah;
unsigned long psmDurationMs;
unsigned long edrxDurationMs;
unsigned long connectedDurationMs;
unsigned long txDurationMs;
unsigned long rxDurationMs;
int transmissionCount;
int pageCheckCount;
};
struct TimerState {
unsigned long t3412StartMs;
unsigned long t3324StartMs;
unsigned long edrxCycleStartMs;
bool t3412Running;
bool t3324Running;
bool psmEnabled;
bool edrxEnabled;
};
struct DataStats {
int totalBytesSent;
int totalBytesReceived;
int messagesSent;
int messagesReceived;
float averageLatencyMs;
};
// ============================================================================
// Global Variables
// ============================================================================
NBIoTState currentState = STATE_POWER_OFF;
CELevel currentCELevel = CE_LEVEL_0;
PowerMode powerMode = POWER_MODE_PSM_EDRX;
SignalQuality signalQuality;
NetworkInfo networkInfo;
PowerStats powerStats;
TimerState timerState;
DataStats dataStats;
unsigned long stateEntryTime = 0;
unsigned long lastStatusUpdate = 0;
unsigned long simulationStartTime = 0;
int repetitionCount = 1;
bool pendingDownlink = false;
int sensorReadingCounter = 0;
// ============================================================================
// Function Declarations
// ============================================================================
void initializeModem();
void processStateMachine();
void updatePowerConsumption();
void printStatus();
void simulateSignalConditions();
void performCellSearch();
void performCellSelection();
void establishRRCConnection();
void performAuthentication();
void enterPSM();
void exitPSM();
void handleEDRXCycle();
void sendUplinkData(const char* data, int length);
void checkForDownlink();
void calculateCERepetitions();
void printStateTransition(NBIoTState from, NBIoTState to);
void printPowerModeInfo();
void printCoverageEnhancementInfo();
const char* getStateName(NBIoTState state);
const char* getCELevelName(CELevel level);
// ============================================================================
// Setup Function
// ============================================================================
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println("========================================");
Serial.println(" NB-IoT FUNDAMENTALS INTERACTIVE LAB");
Serial.println("========================================");
Serial.println();
Serial.println("This simulation demonstrates:");
Serial.println("- Network attach procedure");
Serial.println("- PSM (Power Saving Mode)");
Serial.println("- eDRX (Extended DRX)");
Serial.println("- Coverage Enhancement");
Serial.println();
initializeModem();
simulationStartTime = millis();
Serial.println("Configuration:");
Serial.printf(" PLMN: %s-%s, Band %d\n", PLMN_MCC, PLMN_MNC, BAND_NUMBER);
Serial.printf(" T3412: %d hours, T3324: %d seconds\n",
T3412_VALUE_HOURS, T3324_VALUE_SECONDS);
Serial.printf(" eDRX Cycle: %.2fs, PTW: %.2fs\n",
EDRX_CYCLE_SECONDS, PTW_SECONDS);
Serial.println();
printPowerModeInfo();
Serial.println("\n>>> Initiating network attach...\n");
}
// ============================================================================
// Main Loop
// ============================================================================
void loop() {
processStateMachine();
updatePowerConsumption();
// Periodic status updates (every 5 seconds)
if (millis() - lastStatusUpdate > 5000) {
printStatus();
lastStatusUpdate = millis();
}
// Simulate sensor readings
static unsigned long lastSensorRead = 0;
if (currentState == STATE_REGISTERED || currentState == STATE_PSM ||
currentState == STATE_EDRX_SLEEP) {
if (millis() - lastSensorRead > 30000) {
sensorReadingCounter++;
char payload[64];
snprintf(payload, sizeof(payload),
"{\"id\":%d,\"temp\":%.1f,\"bat\":%d}",
sensorReadingCounter,
20.0 + random(-50, 50) / 10.0,
95 - sensorReadingCounter / 10);
Serial.println("\n========================================");
Serial.printf(">>> SENSOR READING #%d\n", sensorReadingCounter);
Serial.printf(">>> Payload: %s (%d bytes)\n", payload, strlen(payload));
Serial.println("========================================");
sendUplinkData(payload, strlen(payload));
lastSensorRead = millis();
}
}
delay(100);
}
// ============================================================================
// Modem Initialization
// ============================================================================
void initializeModem() {
signalQuality.rsrp = -105;
signalQuality.rsrq = -10;
signalQuality.sinr = 5;
signalQuality.cellId = 123;
signalQuality.earfcn = EARFCN;
strcpy(networkInfo.mcc, PLMN_MCC);
strcpy(networkInfo.mnc, PLMN_MNC);
networkInfo.band = BAND_NUMBER;
networkInfo.tac = 12345;
networkInfo.attached = false;
networkInfo.regStatus = REG_NOT_REGISTERED;
memset(&powerStats, 0, sizeof(powerStats));
memset(&timerState, 0, sizeof(timerState));
memset(&dataStats, 0, sizeof(dataStats));
timerState.psmEnabled = true;
timerState.edrxEnabled = true;
currentState = STATE_CELL_SEARCH;
stateEntryTime = millis();
currentCELevel = (CELevel)INITIAL_CE_LEVEL;
}
// ============================================================================
// State Machine Processing
// ============================================================================
void processStateMachine() {
unsigned long timeInState = millis() - stateEntryTime;
NBIoTState previousState = currentState;
switch (currentState) {
case STATE_CELL_SEARCH:
if (timeInState >= CELL_SEARCH_TIME_MS) {
performCellSearch();
currentState = STATE_CELL_SELECTION;
stateEntryTime = millis();
printStateTransition(previousState, currentState);
}
break;
case STATE_CELL_SELECTION:
if (timeInState >= 500) {
performCellSelection();
currentState = STATE_RRC_CONNECTING;
stateEntryTime = millis();
printStateTransition(previousState, currentState);
}
break;
case STATE_RRC_CONNECTING:
if (timeInState >= RRC_CONNECT_TIME_MS) {
establishRRCConnection();
currentState = STATE_AUTHENTICATING;
stateEntryTime = millis();
printStateTransition(previousState, currentState);
}
break;
case STATE_AUTHENTICATING:
if (timeInState >= AUTHENTICATION_TIME_MS) {
performAuthentication();
currentState = STATE_REGISTERED;
stateEntryTime = millis();
networkInfo.attached = true;
networkInfo.regStatus = REG_REGISTERED_HOME;
printStateTransition(previousState, currentState);
timerState.t3412StartMs = millis();
timerState.t3412Running = true;
timerState.t3324StartMs = millis();
timerState.t3324Running = true;
Serial.println("\n*** SUCCESSFULLY ATTACHED TO NETWORK ***\n");
Serial.printf("PSM timer T3324: %d seconds until sleep\n", T3324_VALUE_SECONDS);
}
break;
case STATE_REGISTERED:
if (timerState.t3324Running) {
unsigned long t3324Elapsed = millis() - timerState.t3324StartMs;
if (t3324Elapsed >= (T3324_VALUE_SECONDS * 1000)) {
timerState.t3324Running = false;
if (timerState.psmEnabled) {
enterPSM();
currentState = STATE_PSM;
stateEntryTime = millis();
printStateTransition(previousState, currentState);
} else if (timerState.edrxEnabled) {
currentState = STATE_EDRX_SLEEP;
stateEntryTime = millis();
timerState.edrxCycleStartMs = millis();
printStateTransition(previousState, currentState);
}
}
}
break;
case STATE_PSM:
handleEDRXCycle();
break;
case STATE_EDRX_SLEEP:
handleEDRXCycle();
break;
case STATE_EDRX_PAGING:
if (timeInState >= (PTW_SECONDS * 1000)) {
checkForDownlink();
powerStats.pageCheckCount++;
if (pendingDownlink) {
currentState = STATE_RRC_CONNECTING;
pendingDownlink = false;
} else {
currentState = timerState.psmEnabled ? STATE_PSM : STATE_EDRX_SLEEP;
timerState.edrxCycleStartMs = millis();
}
stateEntryTime = millis();
printStateTransition(previousState, currentState);
}
break;
case STATE_DATA_TRANSFER:
if (timeInState >= DATA_TRANSFER_TIME_MS * repetitionCount) {
Serial.println(" Data transfer complete");
powerStats.transmissionCount++;
timerState.t3324StartMs = millis();
timerState.t3324Running = true;
currentState = STATE_REGISTERED;
stateEntryTime = millis();
printStateTransition(previousState, currentState);
Serial.printf(" T3324 restarted: %d sec until PSM\n", T3324_VALUE_SECONDS);
}
break;
default:
break;
}
}
// ============================================================================
// Network Procedures
// ============================================================================
void performCellSearch() {
Serial.println("--- CELL SEARCH ---");
Serial.println("1. Scanning NB-IoT bands...");
Serial.println("2. Detecting NPSS/NSSS...");
Serial.println("3. Reading MIB-NB...");
Serial.println("4. Reading SIB1-NB, SIB2-NB...");
simulateSignalConditions();
Serial.printf("\nFound cell: PCI=%d, EARFCN=%d\n",
signalQuality.cellId, signalQuality.earfcn);
Serial.printf("Signal: RSRP=%d dBm, RSRQ=%d dB, SINR=%d dB\n",
signalQuality.rsrp, signalQuality.rsrq, signalQuality.sinr);
}
void performCellSelection() {
Serial.println("\n--- CELL SELECTION ---");
if (signalQuality.rsrp >= -110) {
currentCELevel = CE_LEVEL_0;
Serial.println("Coverage: NORMAL (CE Level 0)");
} else if (signalQuality.rsrp >= -130) {
currentCELevel = CE_LEVEL_1;
Serial.println("Coverage: EXTENDED (CE Level 1)");
} else {
currentCELevel = CE_LEVEL_2;
Serial.println("Coverage: EXTREME (CE Level 2)");
}
calculateCERepetitions();
}
void establishRRCConnection() {
Serial.println("\n--- RRC CONNECTION ---");
Serial.println("1. Sending NPRACH preamble...");
Serial.printf(" (Repetitions: %d for CE Level %d)\n", repetitionCount, currentCELevel);
Serial.println("2. Received RAR...");
Serial.println("3. Sending RRC Connection Request...");
Serial.println("4. Received RRC Connection Setup...");
}
void performAuthentication() {
Serial.println("\n--- AUTHENTICATION ---");
Serial.println("1. EPS-AKA procedure...");
Serial.println("2. NAS Security Mode Command...");
Serial.println("3. Attach Accept received...");
Serial.println("4. Attach Complete sent...");
}
// ============================================================================
// Power Saving Functions
// ============================================================================
void enterPSM() {
Serial.println("\n*** ENTERING PSM ***");
Serial.println("Radio: OFF");
Serial.printf("Power: %.1f uA\n", POWER_IDLE_MA * 1000);
Serial.println("Device is now UNREACHABLE");
}
void exitPSM() {
unsigned long psmDuration = millis() - stateEntryTime;
powerStats.psmDurationMs += psmDuration;
Serial.printf("\n>>> Exiting PSM (slept %.1f sec)\n", psmDuration / 1000.0);
}
void handleEDRXCycle() {
unsigned long edrxElapsed = millis() - timerState.edrxCycleStartMs;
if (edrxElapsed >= (EDRX_CYCLE_SECONDS * 1000)) {
NBIoTState previousState = currentState;
currentState = STATE_EDRX_PAGING;
timerState.edrxCycleStartMs = millis();
Serial.println("\n--- eDRX Paging Window ---");
Serial.println("Checking for downlink...");
stateEntryTime = millis();
printStateTransition(previousState, currentState);
}
}
// ============================================================================
// Data Transfer Functions
// ============================================================================
void sendUplinkData(const char* data, int length) {
if (currentState == STATE_PSM) {
exitPSM();
}
Serial.println("\n--- UPLINK TRANSMISSION ---");
Serial.printf("Payload: %d bytes\n", length);
Serial.printf("CE Level %d: %dx repetitions\n", currentCELevel, repetitionCount);
Serial.printf("TX time: %d ms\n", DATA_TRANSFER_TIME_MS * repetitionCount);
dataStats.totalBytesSent += length;
dataStats.messagesSent++;
NBIoTState previousState = currentState;
currentState = STATE_DATA_TRANSFER;
stateEntryTime = millis();
powerStats.txDurationMs += DATA_TRANSFER_TIME_MS * repetitionCount;
printStateTransition(previousState, currentState);
}
void checkForDownlink() {
int chance = random(100);
if (chance < 5) {
pendingDownlink = true;
Serial.println(" Paging received - downlink pending!");
} else {
pendingDownlink = false;
Serial.println(" No pending downlink");
}
}
// ============================================================================
// Coverage Enhancement Functions
// ============================================================================
void calculateCERepetitions() {
switch (currentCELevel) {
case CE_LEVEL_0: repetitionCount = 1; break;
case CE_LEVEL_1: repetitionCount = 8; break;
case CE_LEVEL_2: repetitionCount = 64; break;
}
printCoverageEnhancementInfo();
}
void simulateSignalConditions() {
int scenario = random(4);
switch (scenario) {
case 0:
signalQuality.rsrp = -85 + random(-10, 10);
signalQuality.rsrq = -8 + random(-3, 3);
signalQuality.sinr = 15 + random(-5, 5);
Serial.println("Scenario: Outdoor - normal coverage");
break;
case 1:
signalQuality.rsrp = -105 + random(-10, 10);
signalQuality.rsrq = -12 + random(-3, 3);
signalQuality.sinr = 5 + random(-3, 3);
Serial.println("Scenario: Indoor - moderate");
break;
case 2:
signalQuality.rsrp = -125 + random(-10, 10);
signalQuality.rsrq = -16 + random(-3, 3);
signalQuality.sinr = -2 + random(-3, 3);
Serial.println("Scenario: Deep indoor - basement");
break;
case 3:
signalQuality.rsrp = -138 + random(-5, 5);
signalQuality.rsrq = -19 + random(-2, 2);
signalQuality.sinr = -8 + random(-5, 5);
Serial.println("Scenario: Extreme - near MCL limit");
break;
}
}
// ============================================================================
// Power Consumption Tracking
// ============================================================================
void updatePowerConsumption() {
static unsigned long lastUpdate = 0;
unsigned long now = millis();
unsigned long elapsed = now - lastUpdate;
if (lastUpdate == 0) {
lastUpdate = now;
return;
}
float hours = elapsed / 3600000.0;
float energyUsed = 0;
switch (currentState) {
case STATE_PSM:
energyUsed = hours * POWER_IDLE_MA;
powerStats.psmDurationMs += elapsed;
break;
case STATE_EDRX_SLEEP:
energyUsed = hours * POWER_EDRX_MA;
powerStats.edrxDurationMs += elapsed;
break;
case STATE_EDRX_PAGING:
case STATE_RRC_IDLE:
energyUsed = hours * POWER_RX_MA;
powerStats.rxDurationMs += elapsed;
break;
case STATE_CELL_SEARCH:
energyUsed = hours * POWER_SEARCH_MA;
break;
case STATE_DATA_TRANSFER:
energyUsed = hours * POWER_TX_MA;
break;
default:
energyUsed = hours * POWER_RX_MA;
powerStats.connectedDurationMs += elapsed;
break;
}
powerStats.totalEnergyMah += energyUsed;
lastUpdate = now;
}
// ============================================================================
// Status Display Functions
// ============================================================================
void printStatus() {
unsigned long runtime = millis() - simulationStartTime;
float runtimeHours = runtime / 3600000.0;
Serial.println("\n========== STATUS ==========");
Serial.printf("State: %s\n", getStateName(currentState));
Serial.printf("Runtime: %.2f hours\n", runtimeHours);
Serial.printf("Registration: %s\n", networkInfo.attached ? "ATTACHED" : "DETACHED");
Serial.printf("CE Level: %d (%s)\n", currentCELevel, getCELevelName(currentCELevel));
Serial.printf("Signal: RSRP=%d dBm\n", signalQuality.rsrp);
Serial.printf("Messages TX: %d, Bytes: %d\n",
dataStats.messagesSent, dataStats.totalBytesSent);
float avgCurrentMa = (powerStats.totalEnergyMah / runtimeHours);
float batteryLifeYears = (2400.0 / avgCurrentMa) / (24 * 365);
Serial.printf("Avg current: %.3f mA\n", avgCurrentMa);
Serial.printf("Projected battery life: %.1f years (2400mAh)\n", batteryLifeYears);
Serial.println("============================");
}
void printStateTransition(NBIoTState from, NBIoTState to) {
Serial.printf("\n>>> State: %s -> %s\n", getStateName(from), getStateName(to));
}
void printPowerModeInfo() {
Serial.println("--- POWER MODE INFO ---");
Serial.println("PSM: Deep sleep (~3 uA), radio OFF");
Serial.println("eDRX: Light sleep (~0.5 mA), periodic wake");
Serial.println("Current config: PSM + eDRX combined");
}
void printCoverageEnhancementInfo() {
Serial.printf("\nCE Analysis: RSRP=%d dBm, Level=%d, Rep=%dx\n",
signalQuality.rsrp, currentCELevel, repetitionCount);
}
// ============================================================================
// Utility Functions
// ============================================================================
const char* getStateName(NBIoTState state) {
switch (state) {
case STATE_POWER_OFF: return "POWER_OFF";
case STATE_CELL_SEARCH: return "CELL_SEARCH";
case STATE_CELL_SELECTION: return "CELL_SELECTION";
case STATE_RRC_IDLE: return "RRC_IDLE";
case STATE_RRC_CONNECTING: return "RRC_CONNECTING";
case STATE_RRC_CONNECTED: return "RRC_CONNECTED";
case STATE_AUTHENTICATING: return "AUTHENTICATING";
case STATE_REGISTERED: return "REGISTERED";
case STATE_DATA_TRANSFER: return "DATA_TRANSFER";
case STATE_PSM: return "PSM_SLEEP";
case STATE_EDRX_SLEEP: return "eDRX_SLEEP";
case STATE_EDRX_PAGING: return "eDRX_PAGING";
default: return "UNKNOWN";
}
}
const char* getCELevelName(CELevel level) {
switch (level) {
case CE_LEVEL_0: return "NORMAL";
case CE_LEVEL_1: return "EXTENDED";
case CE_LEVEL_2: return "EXTREME";
default: return "UNKNOWN";
}
}1132.5 Understanding the Simulation Output
As the simulation runs, observe these key behaviors:
1132.5.1 State Machine Progression
The simulation follows the real NB-IoT attach procedure:
- CELL_SEARCH: Device scans for NB-IoT cells using NPSS/NSSS synchronization signals
- CELL_SELECTION: Evaluates signal quality and selects appropriate Coverage Enhancement level
- RRC_CONNECTING: Establishes Radio Resource Control connection via NPRACH
- AUTHENTICATING: Performs EPS-AKA mutual authentication with the network
- REGISTERED: Successfully attached - T3324 (active timer) starts countdown
- PSM_SLEEP: Deep sleep mode (3 uA) - radio completely off
- eDRX cycles: Periodic wake-ups to check for downlink messages
1132.6 Challenge Exercises
Objective: Understand the impact of T3324 (active timer) on battery life.
Task:
- Change
T3324_VALUE_SECONDSfrom 30 to 5 - Observe how quickly the device enters PSM after data transmission
- Calculate the battery life improvement
Questions to answer:
- What is the trade-off of a very short T3324?
- When would you want a longer T3324 value?
Objective: Experience CE Level 2 (extreme coverage) behavior.
Task:
- Modify the
simulateSignalConditions()function to always return scenario 3 (extreme coverage) - Observe the increased repetition count
- Note the impact on transmission time and power consumption
Modification:
void simulateSignalConditions() {
// Force extreme coverage scenario
signalQuality.rsrp = -138;
signalQuality.rsrq = -19;
signalQuality.sinr = -8;
Serial.println("Scenario: Extreme coverage - near MCL limit");
}Objective: Quantify the difference between PSM-only, eDRX-only, and combined modes.
Task:
- Run simulation with
timerState.edrxEnabled = false(PSM only) - Run with
timerState.psmEnabled = false(eDRX only) - Compare battery life projections from the status reports
Analysis questions:
- Which mode provides best battery life?
- Which mode allows fastest downlink response?
- What use cases favor each approach?
1132.7 Expected Outcomes
After completing this lab, you should be able to:
- Explain the NB-IoT attach procedure including cell search and authentication
- Describe PSM operation and how T3412/T3324 timers control sleep behavior
- Compare PSM vs eDRX trade-offs for different application requirements
- Calculate battery life impact of different power-saving configurations
- Identify Coverage Enhancement levels based on signal quality measurements
- Understand repetition trade-offs between reliability and power/capacity
1132.8 Simulation vs Reality
This simulation demonstrates NB-IoT concepts but differs from real deployments:
What this simulation shows accurately:
- State machine progression and timing relationships
- Power consumption ratios between states
- Coverage Enhancement level selection logic
- PSM and eDRX timer behavior
What requires real hardware/network:
- Actual RF signal measurement (RSRP, RSRQ, SINR)
- Real carrier authentication and SIM provisioning
- True power consumption measurements
- Network-negotiated timer values (carriers may override requests)
- SCEF integration for Control Plane optimization
For hands-on NB-IoT development:
- Use modules like Quectel BC95, u-blox SARA-N2, or Nordic nRF9160
- Obtain NB-IoT SIM cards from carriers (AT&T, Verizon, T-Mobile in US)
- Consider IoT platforms like Soracom, Hologram, or 1NCE for connectivity
1132.9 Summary
- NB-IoT attach procedure involves cell search, RRC connection, authentication, and registration
- PSM (Power Saving Mode) achieves 3 uA sleep current by completely disabling the radio
- T3324 controls active time before entering PSM; shorter values save power but reduce downlink opportunity
- Coverage Enhancement uses repetitions to improve reliability in poor signal conditions
- Battery life projection depends on sleep current, TX duration, message frequency, and CE level
- This simulation provides conceptual understanding; real deployments require certified modules and carrier connectivity
1132.10 Whatβs Next
Continue your NB-IoT learning journey with these related topics:
- NB-IoT Comprehensive Review - Test your knowledge with comprehensive quiz questions
- LTE-M Fundamentals - Learn about the alternative cellular IoT technology
- Cellular IoT Comparison - Compare NB-IoT, LTE-M, and other cellular technologies