78  Wireless Propagation: Practical Considerations and Lab

78.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Identify the key factors affecting indoor vs outdoor wireless deployment
  • Select appropriate antenna types for different IoT applications
  • Apply engineering trade-offs to wireless system design decisions
  • Measure and interpret RSSI values from Wi-Fi networks using an ESP32
  • Simulate packet transmission with acknowledgment and retransmission mechanisms
  • Correlate distance and interference with signal quality through hands-on experimentation

78.2 Prerequisites

Before diving into this chapter, you should be comfortable with:


78.3 Practical Propagation Considerations

78.3.1 Indoor vs Outdoor Deployment

Indoor challenges: - Walls reduce signal (3-15 dB per wall) - Metal structures (elevators, ductwork) block signals - Furniture and people absorb signals - Multipath from reflections

Outdoor challenges: - Distance (requires more power or better sensitivity) - Weather (rain attenuation at higher frequencies) - Interference from other systems - Regulatory power limits

78.3.2 Antenna Considerations

Antenna Type Gain Pattern Best For
Chip antenna 0 dBi Omnidirectional Size-constrained devices
Dipole 2-3 dBi Omnidirectional General purpose
Monopole (whip) 2-5 dBi Omnidirectional Portable devices
Patch 6-9 dBi Directional Ceiling mount, fixed direction
Yagi 10-15 dBi Highly directional Point-to-point links
Parabolic 20-30 dBi Very narrow beam Long-range backhaul
NoteAntenna Gain Rule of Thumb

Every 3 dB of antenna gain doubles your effective range (or lets you halve your transmit power for the same range).


78.4 Engineering Tradeoffs

WarningTradeoff: Sub-GHz vs 2.4 GHz Frequency Band

Option A: Sub-GHz (868/915 MHz) - 9 dB less path loss than 2.4 GHz at same distance, excellent wall penetration, 5-15 km outdoor range, longer battery life due to fewer retransmissions. Cost: Lower data rates (0.3-50 kbps), larger antennas (8-17 cm), region-specific regulations

Option B: 2.4 GHz (Wi-Fi, BLE, Zigbee) - Higher data rates (up to 2 Mbps), smaller antennas (3 cm), global ISM band availability, mature ecosystem with commodity pricing. Cost: 50-200m typical range, poor penetration through walls, crowded spectrum with Wi-Fi/microwave interference

Decision factors: Choose sub-GHz for outdoor deployments, large facilities, or through-wall coverage (agriculture, smart city, building-wide sensors). Choose 2.4 GHz for high-bandwidth needs (cameras), small form factors (wearables), or when leveraging existing Wi-Fi infrastructure. Consider hybrid: sub-GHz for wide-area sensors, 2.4 GHz for localized high-bandwidth devices.

WarningTradeoff: Transmit Power vs Battery Life

Option A: Higher Transmit Power - Extended range, better link margin, more reliable connections in challenging environments. Cost: Proportionally higher power consumption, may hit regulatory limits (14 dBm EU, 30 dBm US), potential interference with nearby devices

Option B: Lower Transmit Power with Better Antennas/Sensitivity - Every 3 dB antenna gain doubles effective range without battery cost, receiver sensitivity improvements extend range. Cost: Larger/more expensive antennas, may require external antenna connectors, directional antennas limit coverage pattern

Decision factors: For battery-powered devices, invest in better antennas and sensitive receivers rather than higher transmit power. A 6 dBi antenna gain provides 4x effective range versus 0 dBi at same battery cost. For mains-powered gateways, maximize transmit power within regulatory limits. Always calculate link budget before deployment.

WarningTradeoff: Link Margin vs Cost

Option A: Conservative Link Margin (20-30 dB) - Reliable operation through seasonal changes, weather, vegetation growth, and interference variations. Cost: Higher transmit power or better antennas, potentially more gateway/repeater infrastructure

Option B: Aggressive Link Margin (10-15 dB) - Lower infrastructure cost, smaller devices with simpler antennas, meets requirements under ideal conditions. Cost: Intermittent connectivity during rain/snow, signal degradation as vegetation grows, vulnerability to new interference sources

Decision factors: Mission-critical applications (safety systems, medical alerts) should target 25-30 dB margin. Cost-sensitive deployments can start with 15 dB margin but must plan for remediation. Outdoor deployments need higher margins than indoor due to weather variability. Always conduct site surveys at worst-case times (peak interference, full foliage).

WarningTradeoff: Omnidirectional vs Directional Antennas

Option A (Omnidirectional): 360-degree coverage with 0-5 dBi gain. Simple deployment - no alignment needed. Works for mobile devices and multi-direction communication. Typical gain: Chip antenna 0 dBi, dipole 2-3 dBi, ground plane 5-6 dBi. Cost: Lower antenna cost, but may need more transmit power or shorter range.

Option B (Directional): Concentrated beam with 6-20+ dBi gain in specific direction. Yagi: 10-15 dBi, 30-60 degree beam. Parabolic: 20-30 dBi, 5-15 degree beam. Patch: 6-9 dBi, 60-90 degree beam. Benefit: Every 3 dB gain doubles effective range. Cost: Requires precise alignment, fixed installation, reduced coverage angle.

Decision Factors: Choose omnidirectional for gateways serving devices in all directions, mobile devices, or when coverage pattern is unknown. Choose directional for point-to-point links (building-to-building), extending range to specific remote areas, or reducing interference from unwanted directions. Key calculation: A 12 dBi Yagi provides 4x the range of a 0 dBi chip antenna at same transmit power - critical for reaching distant sensors without boosting power.

WarningTradeoff: Single High-Power Gateway vs Multiple Low-Power Gateways

Option A (Single High-Power Gateway): One gateway with maximum regulatory transmit power (14 dBm EU, 30 dBm US) and high-gain antenna (6-12 dBi). Covers 2-10 km radius depending on environment. Lower infrastructure cost. Single point of management. Downside: Single point of failure, edge devices may struggle with uplink (they have power constraints even if gateway doesnโ€™t).

Option B (Multiple Low-Power Gateways): Distributed gateways every 1-3 km with standard antennas. Redundant coverage - if one fails, neighbors provide backup. Better uplink reliability since devices are closer. Enables location via RSSI triangulation. Cost: More infrastructure ($500-1,500 per gateway), more installation sites, more backhaul connections needed.

Decision Factors: Choose single gateway for pilot deployments, cost-constrained projects, or areas with good line-of-sight. Choose multiple gateways when 99.9%+ uptime is required, deploying in urban environments with obstacles, or when location tracking is needed. Key insight: Uplink (device to gateway) is usually the limiting factor - a powerful gateway doesnโ€™t help if battery-powered sensors canโ€™t transmit back. Adding gateways improves both coverage and sensor battery life by allowing lower transmit power.


78.5 Knowledge Check

Check your understanding of key propagation ideas:

Question 1: At the same distance and transmit power, which link typically has lower free-space path loss?

Explanation: Lower frequency means lower free-space path loss (FSPL). Higher-frequency links generally need more link budget or closer distances for the same reliability.

Question 2: What does 0 dBm correspond to?

Explanation: dBm is an absolute power unit referenced to 1 mW. So 0 dBm = 1 mW, +10 dBm = 10 mW, and -10 dBm = 0.1 mW.

Question 3: In free space, doubling the distance increases path loss by approximately:

Explanation: FSPL includes a 20 log10(distance) term, so doubling distance adds 20 log10(2) approximately 6 dB.

Question 4: Why do engineers add a fading margin to a link budget?

Explanation: Real links fluctuate. A fading margin absorbs variability from multipath fading, body/foliage loss, weather, and interference so the link remains reliable over time.

Question 5: A transmitter outputs +20 dBm and the antenna has 3 dBi gain. What is the EIRP (Effective Isotropic Radiated Power)?

Explanation: EIRP = Tx Power + Antenna Gain. So 20 dBm + 3 dBi = 23 dBm. Note: dBi means gain relative to an isotropic (ideal point) antenna. EIRP represents how much power would need to be radiated by a perfect isotropic antenna to achieve the same signal strength.

Question 6: An indoor IoT deployment at 2.4 GHz experiences 15 dB path loss through walls. What is the primary cause?

Explanation: A. Walls cause additional loss beyond free-space through absorption (energy converted to heat in the material) and reflection (signal bouncing back). Typical wall losses: drywall 3-5 dB, concrete 10-15 dB, metal-reinforced 15-25 dB. This is why indoor range is much shorter than outdoor.

Question 7: Why does rain significantly affect 60 GHz mmWave signals but not 900 MHz signals?

Explanation: D. Rain attenuation depends on the ratio of raindrop size to wavelength. At 60 GHz (5mm wavelength), raindrops (1-5mm) are comparable in size, causing significant Mie scattering and water molecule absorption. At 900 MHz (33cm wavelength), raindrops are tiny compared to the wavelength, so rain has minimal effect.

Question 8: A receiver has sensitivity of -100 dBm and requires 10 dB SNR minimum. If the noise floor is -110 dBm, what is the minimum received signal strength for reliable operation?

Explanation: B. The receiver sensitivity (-100 dBm) already accounts for the required SNR. At -100 dBm signal with -110 dBm noise floor, SNR = -100 - (-110) = 10 dB, exactly meeting the requirement. Below -100 dBm, SNR drops and errors increase.


78.6 Lab: Wireless Communication Fundamentals

NoteLearning Objectives

By completing this interactive hardware lab, you will be able to:

  • Measure and interpret RSSI (Received Signal Strength Indicator) values from Wi-Fi networks
  • Visualize signal quality through LED indicators representing different RSSI thresholds
  • Simulate packet transmission with acknowledgment (ACK) and retransmission mechanisms
  • Understand interference effects by observing packet loss under simulated interference conditions
  • Correlate distance with signal quality through simulated range scenarios
  • Analyze link budget concepts by observing how signal strength affects communication reliability
  • Implement adaptive communication based on real-time signal quality measurements

Prerequisites: Basic Arduino/C++ syntax, understanding of wireless propagation concepts from this chapter

Estimated Time: 45-60 minutes

78.6.1 What You Will Learn

This hands-on lab demonstrates the core concepts of wireless communication that were covered theoretically in this chapter:

Concept Theory Section Lab Demonstration
RSSI measurement Understanding Signal Strength Real Wi-Fi RSSI readings with LED visualization
Link quality Link Budget Packet success rate vs signal strength
Interference RF Interference Patterns Simulated interference affecting packet delivery
Fading Fading and Multipath Random signal variations and their effects
Path loss Free Space Path Loss Distance-based signal attenuation simulation

78.6.2 Components

Component Purpose Wokwi Element
ESP32 DevKit Wi-Fi-enabled microcontroller for RSSI measurement esp32:devkit-v1
Green LED Excellent signal indicator (RSSI > -50 dBm) led:green
Yellow LED Good signal indicator (-50 to -70 dBm) led:yellow
Orange LED Fair signal indicator (-70 to -80 dBm) led:orange
Red LED Poor signal indicator (< -80 dBm) led:red
Blue LED Packet transmission activity indicator led:blue
White LED Acknowledgment received indicator led:white
Push Button 1 Simulate interference burst button
Push Button 2 Simulate distance increase (weaker signal) button
Push Button 3 Send test packet / Reset statistics button
Resistors (6x 220 ohm) Current limiting for LEDs resistor

78.6.3 Interactive Wokwi Simulator

Use the embedded simulator below to explore wireless communication fundamentals. Wire the circuit as shown, paste the code, and click โ€œStart Simulationโ€.

TipSimulator Tips
  • Wire first: Connect all components before pasting code
  • Paste code: Copy the complete code below into the editor
  • Run: Click the green โ€œPlayโ€ button to compile and run
  • Serial Monitor: View detailed RSSI data, packet statistics, and link analysis
  • Buttons: Use on-screen buttons to simulate interference, distance changes, and packet transmission
  • Wi-Fi Note: In Wokwi, Wi-Fi scanning shows simulated networks; the code demonstrates RSSI concepts regardless of actual Wi-Fi connectivity

78.6.4 Circuit Connections

Wire the circuit in Wokwi before entering the code:

ESP32 Pin Connections:
----------------------
GPIO 2  --> Green LED (+)  --> 220 ohm Resistor --> GND  (Excellent signal)
GPIO 4  --> Yellow LED (+) --> 220 ohm Resistor --> GND  (Good signal)
GPIO 5  --> Orange LED (+) --> 220 ohm Resistor --> GND  (Fair signal)
GPIO 18 --> Red LED (+)    --> 220 ohm Resistor --> GND  (Poor signal)
GPIO 19 --> Blue LED (+)   --> 220 ohm Resistor --> GND  (TX activity)
GPIO 21 --> White LED (+)  --> 220 ohm Resistor --> GND  (ACK received)
GPIO 15 --> Button 1       --> GND  (Interference simulation)
GPIO 16 --> Button 2       --> GND  (Distance simulation)
GPIO 17 --> Button 3       --> GND  (Send packet / Reset)

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'fontSize': '12px'}}}%%
graph LR
    subgraph ESP32["ESP32 DevKit V1"]
        G2[GPIO 2]
        G4[GPIO 4]
        G5[GPIO 5]
        G18[GPIO 18]
        G19[GPIO 19]
        G21[GPIO 21]
        G15[GPIO 15]
        G16[GPIO 16]
        G17[GPIO 17]
        GND[GND]
    end

    subgraph SignalLEDs["Signal Quality LEDs"]
        GL[Green LED<br/>Excellent]
        YL[Yellow LED<br/>Good]
        OL[Orange LED<br/>Fair]
        RL[Red LED<br/>Poor]
    end

    subgraph CommLEDs["Communication LEDs"]
        BL[Blue LED<br/>TX Activity]
        WL[White LED<br/>ACK Received]
    end

    subgraph Buttons["Control Buttons"]
        B1[Button 1<br/>Interference]
        B2[Button 2<br/>Distance]
        B3[Button 3<br/>Send/Reset]
    end

    G2 --> GL --> GND
    G4 --> YL --> GND
    G5 --> OL --> GND
    G18 --> RL --> GND
    G19 --> BL --> GND
    G21 --> WL --> GND
    G15 --> B1 --> GND
    G16 --> B2 --> GND
    G17 --> B3 --> GND

    style ESP32 fill:#2C3E50,color:#fff
    style GL fill:#16A085,color:#fff
    style YL fill:#F1C40F,color:#000
    style OL fill:#E67E22,color:#fff
    style RL fill:#E74C3C,color:#fff
    style BL fill:#3498DB,color:#fff
    style WL fill:#ECF0F1,color:#2C3E50

Figure 78.1: Circuit diagram showing ESP32 connections to signal quality LEDs, communication LEDs, and control buttons for the wireless communication lab.

78.6.5 Complete Arduino Code

Copy and paste this complete code into the Wokwi simulator:

// =============================================================================
// Wireless Communication Fundamentals Lab - ESP32
// Demonstrates: RSSI measurement, packet transmission, interference, link budget
// Educational IoT Lab - Wireless Propagation Concepts
// =============================================================================

#include <WiFi.h>

// =============================================================================
// PIN DEFINITIONS
// =============================================================================

// Signal Quality LEDs (RSSI thresholds)
#define LED_EXCELLENT   2    // Green  - RSSI > -50 dBm
#define LED_GOOD        4    // Yellow - RSSI -50 to -70 dBm
#define LED_FAIR        5    // Orange - RSSI -70 to -80 dBm
#define LED_POOR        18   // Red    - RSSI < -80 dBm

// Communication Status LEDs
#define LED_TX          19   // Blue  - Packet transmission
#define LED_ACK         21   // White - Acknowledgment received

// Control Buttons
#define BTN_INTERFERENCE 15  // Simulate RF interference
#define BTN_DISTANCE     16  // Simulate distance increase
#define BTN_SEND         17  // Send packet / Long press = reset

// =============================================================================
// RSSI THRESHOLDS (dBm) - Based on standard Wi-Fi quality metrics
// =============================================================================

#define RSSI_EXCELLENT  -50  // Very close to AP, excellent quality
#define RSSI_GOOD       -60  // Good signal, reliable connection
#define RSSI_FAIR       -70  // Acceptable, may have occasional issues
#define RSSI_POOR       -80  // Weak signal, packet loss likely
#define RSSI_UNUSABLE   -90  // Very weak, connection unreliable

// =============================================================================
// WIRELESS SIMULATION PARAMETERS
// =============================================================================

// Path Loss Model Parameters (Log-distance model)
#define PATH_LOSS_EXPONENT    3.0    // Indoor environment (n=2.5-4)
#define REFERENCE_DISTANCE    1.0    // Reference distance in meters
#define REFERENCE_RSSI        -40    // RSSI at 1 meter (dBm)

// Fading Simulation
#define FADING_VARIANCE       8      // Standard deviation for shadow fading (dB)
#define MULTIPATH_VARIANCE    4      // Fast fading variation (dB)

// Interference Parameters
#define INTERFERENCE_DURATION 3000   // Interference burst duration (ms)
#define INTERFERENCE_PENALTY  25     // RSSI reduction during interference (dB)

// Packet Transmission Parameters
#define PACKET_SIZE           64     // Simulated packet size (bytes)
#define BASE_PACKET_LOSS      0.02   // 2% base packet loss rate
#define ACK_TIMEOUT           500    // ACK timeout (ms)
#define MAX_RETRIES           3      // Maximum retransmission attempts

// =============================================================================
// GLOBAL VARIABLES
// =============================================================================

// Wireless State
float simulatedDistance = 10.0;      // Simulated distance in meters
int currentRSSI = -55;               // Current RSSI value (dBm)
int baseRSSI = -55;                  // Base RSSI without fading
bool interferenceActive = false;     // Interference burst active
unsigned long interferenceStartTime = 0;

// Packet Statistics
unsigned long packetsSent = 0;
unsigned long packetsReceived = 0;
unsigned long packetsLost = 0;
unsigned long totalRetries = 0;
float packetLossRate = 0.0;
float averageRetries = 0.0;

// Communication State
bool awaitingAck = false;
unsigned long lastPacketTime = 0;
int currentRetries = 0;
int lastPacketId = 0;

// Button Debouncing
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 200;
unsigned long buttonPressStart = 0;
bool longPressDetected = false;

// Timing
unsigned long lastRSSIUpdate = 0;
unsigned long lastStatsDisplay = 0;
const unsigned long RSSI_UPDATE_INTERVAL = 500;
const unsigned long STATS_DISPLAY_INTERVAL = 5000;

// Wi-Fi Scanning
int networksFound = 0;
String strongestNetwork = "";
int strongestRSSI = -100;

// =============================================================================
// SETUP FUNCTION
// =============================================================================

void setup() {
    Serial.begin(115200);
    delay(1000);

    // Initialize LED pins
    pinMode(LED_EXCELLENT, OUTPUT);
    pinMode(LED_GOOD, OUTPUT);
    pinMode(LED_FAIR, OUTPUT);
    pinMode(LED_POOR, OUTPUT);
    pinMode(LED_TX, OUTPUT);
    pinMode(LED_ACK, OUTPUT);

    // Initialize button pins with internal pullup
    pinMode(BTN_INTERFERENCE, INPUT_PULLUP);
    pinMode(BTN_DISTANCE, INPUT_PULLUP);
    pinMode(BTN_SEND, INPUT_PULLUP);

    // Turn off all LEDs initially
    clearAllLEDs();

    // Startup LED sequence
    startupSequence();

    // Print welcome message
    printWelcome();

    // Initialize Wi-Fi in station mode for scanning
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);

    // Initial Wi-Fi scan
    performWiFiScan();

    // Initialize random seed
    randomSeed(analogRead(0) + millis());

    Serial.println("\n=== Lab Ready! ===");
    Serial.println("Press Button 3 to send a packet");
    Serial.println("Press Button 1 to simulate interference");
    Serial.println("Press Button 2 to increase simulated distance");
    Serial.println("Long-press Button 3 (2s) to reset statistics\n");
}

// =============================================================================
// MAIN LOOP
// =============================================================================

void loop() {
    unsigned long currentTime = millis();

    // Update RSSI simulation periodically
    if (currentTime - lastRSSIUpdate >= RSSI_UPDATE_INTERVAL) {
        updateRSSISimulation();
        updateSignalLEDs();
        lastRSSIUpdate = currentTime;
    }

    // Display statistics periodically
    if (currentTime - lastStatsDisplay >= STATS_DISPLAY_INTERVAL) {
        displayStatistics();
        lastStatsDisplay = currentTime;
    }

    // Handle interference timeout
    if (interferenceActive && (currentTime - interferenceStartTime >= INTERFERENCE_DURATION)) {
        interferenceActive = false;
        Serial.println("[INTERFERENCE] Interference burst ended");
        Serial.println("               Signal returning to normal\n");
    }

    // Handle ACK timeout
    if (awaitingAck && (currentTime - lastPacketTime >= ACK_TIMEOUT)) {
        handleAckTimeout();
    }

    // Process button inputs
    handleButtons();
}

// =============================================================================
// RSSI SIMULATION AND CALCULATION
// =============================================================================

void updateRSSISimulation() {
    // Calculate base RSSI using log-distance path loss model
    // PL(d) = PL(d0) + 10 * n * log10(d/d0)
    float pathLoss = 10.0 * PATH_LOSS_EXPONENT * log10(simulatedDistance / REFERENCE_DISTANCE);
    baseRSSI = REFERENCE_RSSI - (int)pathLoss;

    // Add shadow fading (slow fading) - Gaussian distribution
    int shadowFading = (int)(gaussianRandom() * FADING_VARIANCE);

    // Add multipath fading (fast fading) - smaller, faster variations
    int multipathFading = (int)(gaussianRandom() * MULTIPATH_VARIANCE);

    // Calculate current RSSI
    currentRSSI = baseRSSI + shadowFading + multipathFading;

    // Apply interference penalty if active
    if (interferenceActive) {
        currentRSSI -= INTERFERENCE_PENALTY;
    }

    // Clamp RSSI to realistic range
    currentRSSI = constrain(currentRSSI, -100, -20);
}

float gaussianRandom() {
    // Box-Muller transform for Gaussian distribution
    static bool hasSpare = false;
    static float spare;

    if (hasSpare) {
        hasSpare = false;
        return spare;
    }

    float u, v, s;
    do {
        u = (float)random(0, 10000) / 5000.0 - 1.0;
        v = (float)random(0, 10000) / 5000.0 - 1.0;
        s = u * u + v * v;
    } while (s >= 1.0 || s == 0.0);

    s = sqrt(-2.0 * log(s) / s);
    spare = v * s;
    hasSpare = true;
    return u * s;
}

// =============================================================================
// SIGNAL QUALITY LED DISPLAY
// =============================================================================

void updateSignalLEDs() {
    // Clear all signal LEDs first
    digitalWrite(LED_EXCELLENT, LOW);
    digitalWrite(LED_GOOD, LOW);
    digitalWrite(LED_FAIR, LOW);
    digitalWrite(LED_POOR, LOW);

    // Light appropriate LED based on RSSI
    if (currentRSSI >= RSSI_EXCELLENT) {
        digitalWrite(LED_EXCELLENT, HIGH);  // Green - Excellent
    } else if (currentRSSI >= RSSI_GOOD) {
        digitalWrite(LED_GOOD, HIGH);       // Yellow - Good
    } else if (currentRSSI >= RSSI_FAIR) {
        digitalWrite(LED_FAIR, HIGH);       // Orange - Fair
    } else if (currentRSSI >= RSSI_POOR) {
        digitalWrite(LED_POOR, HIGH);       // Red - Poor
    } else {
        // Below -80 dBm: blink red to indicate critical
        digitalWrite(LED_POOR, (millis() / 250) % 2);
    }
}

// =============================================================================
// PACKET TRANSMISSION SIMULATION
// =============================================================================

void sendPacket() {
    if (awaitingAck) {
        Serial.println("[TX] Already awaiting ACK, please wait...");
        return;
    }

    packetsSent++;
    lastPacketId++;
    currentRetries = 0;

    // Visual feedback - TX LED on
    digitalWrite(LED_TX, HIGH);

    Serial.println("\n========================================");
    Serial.printf("[TX] Sending Packet #%d\n", lastPacketId);
    Serial.printf("     Size: %d bytes\n", PACKET_SIZE);
    Serial.printf("     Current RSSI: %d dBm\n", currentRSSI);
    Serial.printf("     Signal Quality: %s\n", getSignalQualityString());
    Serial.printf("     Interference: %s\n", interferenceActive ? "ACTIVE" : "None");

    // Calculate packet loss probability based on RSSI
    float lossProb = calculatePacketLossProbability();
    Serial.printf("     Packet Loss Probability: %.1f%%\n", lossProb * 100);

    // Simulate transmission
    simulateTransmission(lossProb);
}

float calculatePacketLossProbability() {
    // Packet loss probability increases as RSSI decreases
    // Using a sigmoid-like function centered around the fair threshold

    float baseLoss = BASE_PACKET_LOSS;

    if (currentRSSI >= RSSI_EXCELLENT) {
        // Excellent signal: minimal loss
        return baseLoss;
    } else if (currentRSSI >= RSSI_GOOD) {
        // Good signal: low loss
        return baseLoss + 0.02;
    } else if (currentRSSI >= RSSI_FAIR) {
        // Fair signal: moderate loss
        return baseLoss + 0.08;
    } else if (currentRSSI >= RSSI_POOR) {
        // Poor signal: significant loss
        return baseLoss + 0.20;
    } else {
        // Very poor signal: high loss
        float additionalLoss = 0.30 + (RSSI_POOR - currentRSSI) * 0.03;
        return min(baseLoss + additionalLoss, 0.70f);
    }
}

void simulateTransmission(float lossProb) {
    // Determine if packet is lost
    float randomValue = (float)random(0, 1000) / 1000.0;

    if (randomValue < lossProb) {
        // Packet lost - simulate waiting for ACK
        Serial.println("     [SIMULATING] Packet transmitted...");
        awaitingAck = true;
        lastPacketTime = millis();

        // Schedule packet loss (ACK timeout will handle)
        Serial.println("     Status: Awaiting ACK...\n");
    } else {
        // Packet received successfully
        Serial.println("     [SIMULATING] Packet transmitted...");
        delay(50);  // Simulate transmission time

        // Simulate successful reception and ACK
        receiveAck();
    }
}

void receiveAck() {
    packetsReceived++;
    awaitingAck = false;

    // Visual feedback
    digitalWrite(LED_TX, LOW);
    digitalWrite(LED_ACK, HIGH);

    // Calculate latency (simulated)
    int latency = 20 + random(0, 30);  // 20-50ms typical

    Serial.println("     [RX] ACK Received!");
    Serial.printf("     Round-Trip Time: %d ms\n", latency);
    Serial.printf("     Retries needed: %d\n", currentRetries);
    Serial.println("     Status: SUCCESS");
    Serial.println("========================================\n");

    // Brief ACK LED indication
    delay(200);
    digitalWrite(LED_ACK, LOW);

    // Update statistics
    updateStatistics();
}

void handleAckTimeout() {
    currentRetries++;
    totalRetries++;

    Serial.printf("     [TIMEOUT] No ACK received (attempt %d/%d)\n",
                  currentRetries, MAX_RETRIES);

    if (currentRetries >= MAX_RETRIES) {
        // Max retries exceeded - packet lost
        packetsLost++;
        awaitingAck = false;

        digitalWrite(LED_TX, LOW);
        // Flash red LED to indicate loss
        for (int i = 0; i < 3; i++) {
            digitalWrite(LED_POOR, HIGH);
            delay(100);
            digitalWrite(LED_POOR, LOW);
            delay(100);
        }

        Serial.println("     [FAILED] Max retries exceeded - Packet LOST");
        Serial.println("     This demonstrates why link margin is important!");
        Serial.println("========================================\n");

        updateStatistics();
    } else {
        // Retransmit
        Serial.println("     [RETRANSMIT] Attempting retransmission...\n");

        // Quick blink TX LED
        digitalWrite(LED_TX, LOW);
        delay(50);
        digitalWrite(LED_TX, HIGH);

        // Retry with slightly different loss probability (channel may change)
        float lossProb = calculatePacketLossProbability();
        lastPacketTime = millis();
        simulateTransmission(lossProb);
    }
}

// =============================================================================
// INTERFERENCE SIMULATION
// =============================================================================

void triggerInterference() {
    interferenceActive = true;
    interferenceStartTime = millis();

    Serial.println("\n========================================");
    Serial.println("[INTERFERENCE] RF Interference Burst Detected!");
    Serial.println("              Source: Simulated 2.4 GHz interference");
    Serial.printf("              Duration: %d ms\n", INTERFERENCE_DURATION);
    Serial.printf("              RSSI Impact: -%d dB\n", INTERFERENCE_PENALTY);
    Serial.println("              Effect: Increased packet loss, degraded SNR");
    Serial.println("========================================\n");

    // Visual indication - blink all LEDs briefly
    flashAllLEDs(3, 100);
}

// =============================================================================
// DISTANCE SIMULATION
// =============================================================================

void increaseDistance() {
    // Increase simulated distance
    float oldDistance = simulatedDistance;

    if (simulatedDistance < 20) {
        simulatedDistance += 5;
    } else if (simulatedDistance < 50) {
        simulatedDistance += 10;
    } else if (simulatedDistance < 100) {
        simulatedDistance += 25;
    } else {
        simulatedDistance = 10;  // Reset to close range
    }

    // Calculate path loss change
    float oldPathLoss = 10.0 * PATH_LOSS_EXPONENT * log10(oldDistance / REFERENCE_DISTANCE);
    float newPathLoss = 10.0 * PATH_LOSS_EXPONENT * log10(simulatedDistance / REFERENCE_DISTANCE);
    float pathLossChange = newPathLoss - oldPathLoss;

    Serial.println("\n========================================");
    Serial.println("[DISTANCE] Simulated Distance Changed");
    Serial.printf("           Old distance: %.0f m\n", oldDistance);
    Serial.printf("           New distance: %.0f m\n", simulatedDistance);
    Serial.printf("           Path loss change: +%.1f dB\n", pathLossChange);
    Serial.println("           ");
    Serial.println("           This demonstrates the inverse-square law:");
    Serial.println("           Doubling distance adds ~6 dB path loss");
    Serial.println("========================================\n");

    // Update RSSI immediately
    updateRSSISimulation();
    updateSignalLEDs();

    // Print new signal status
    printSignalStatus();
}

// =============================================================================
// BUTTON HANDLING
// =============================================================================

void handleButtons() {
    unsigned long currentTime = millis();

    // Check for button presses with debouncing
    if (currentTime - lastDebounceTime < debounceDelay) {
        return;
    }

    // Button 1: Interference simulation
    if (digitalRead(BTN_INTERFERENCE) == LOW) {
        lastDebounceTime = currentTime;
        triggerInterference();
    }

    // Button 2: Distance increase
    if (digitalRead(BTN_DISTANCE) == LOW) {
        lastDebounceTime = currentTime;
        increaseDistance();
    }

    // Button 3: Send packet / Long press for reset
    static bool btn3WasPressed = false;

    if (digitalRead(BTN_SEND) == LOW) {
        if (!btn3WasPressed) {
            buttonPressStart = currentTime;
            btn3WasPressed = true;
            longPressDetected = false;
        } else if (!longPressDetected && (currentTime - buttonPressStart > 2000)) {
            // Long press detected - reset statistics
            longPressDetected = true;
            resetStatistics();
        }
    } else {
        if (btn3WasPressed && !longPressDetected) {
            // Short press - send packet
            lastDebounceTime = currentTime;
            sendPacket();
        }
        btn3WasPressed = false;
    }
}

// =============================================================================
// STATISTICS AND DISPLAY
// =============================================================================

void updateStatistics() {
    if (packetsSent > 0) {
        packetLossRate = (float)packetsLost / packetsSent * 100.0;
        averageRetries = (float)totalRetries / packetsSent;
    }
}

void displayStatistics() {
    Serial.println("\n--- Link Quality Statistics ---");
    Serial.printf("Current RSSI: %d dBm (%s)\n", currentRSSI, getSignalQualityString());
    Serial.printf("Simulated Distance: %.0f m\n", simulatedDistance);
    Serial.printf("Interference: %s\n", interferenceActive ? "ACTIVE" : "None");
    Serial.println("");
    Serial.printf("Packets Sent: %lu\n", packetsSent);
    Serial.printf("Packets Received: %lu\n", packetsReceived);
    Serial.printf("Packets Lost: %lu\n", packetsLost);
    Serial.printf("Packet Loss Rate: %.1f%%\n", packetLossRate);
    Serial.printf("Total Retries: %lu\n", totalRetries);
    Serial.printf("Avg Retries/Packet: %.2f\n", averageRetries);
    Serial.println("-------------------------------\n");
}

void resetStatistics() {
    packetsSent = 0;
    packetsReceived = 0;
    packetsLost = 0;
    totalRetries = 0;
    packetLossRate = 0.0;
    averageRetries = 0.0;
    simulatedDistance = 10.0;
    interferenceActive = false;
    lastPacketId = 0;

    Serial.println("\n========================================");
    Serial.println("[RESET] All statistics cleared!");
    Serial.println("        Distance reset to 10m");
    Serial.println("        Ready for new measurements");
    Serial.println("========================================\n");

    // Visual feedback
    flashAllLEDs(2, 200);
}

void printSignalStatus() {
    Serial.printf("Signal Status: RSSI = %d dBm\n", currentRSSI);
    Serial.printf("Quality: %s\n", getSignalQualityString());

    // Link budget analysis
    int linkMargin = currentRSSI - RSSI_UNUSABLE;
    Serial.printf("Link Margin: %d dB above minimum\n", linkMargin);

    if (linkMargin > 20) {
        Serial.println("Assessment: Excellent margin, very reliable link");
    } else if (linkMargin > 10) {
        Serial.println("Assessment: Good margin, reliable link");
    } else if (linkMargin > 5) {
        Serial.println("Assessment: Low margin, occasional issues possible");
    } else {
        Serial.println("Assessment: Critical margin, unreliable link!");
    }
}

const char* getSignalQualityString() {
    if (currentRSSI >= RSSI_EXCELLENT) return "EXCELLENT";
    if (currentRSSI >= RSSI_GOOD) return "GOOD";
    if (currentRSSI >= RSSI_FAIR) return "FAIR";
    if (currentRSSI >= RSSI_POOR) return "POOR";
    return "VERY POOR";
}

// =============================================================================
// WIFI SCANNING
// =============================================================================

void performWiFiScan() {
    Serial.println("\n[SCAN] Scanning for Wi-Fi networks...");

    networksFound = WiFi.scanNetworks();

    if (networksFound == 0) {
        Serial.println("[SCAN] No networks found");
        Serial.println("       (This is normal in Wokwi simulator)");
        Serial.println("       Using simulated RSSI values for demonstration\n");
    } else {
        Serial.printf("[SCAN] Found %d networks:\n", networksFound);

        strongestRSSI = -100;
        strongestNetwork = "";

        for (int i = 0; i < min(networksFound, 5); i++) {
            Serial.printf("       %d: %s (%d dBm) %s\n",
                         i + 1,
                         WiFi.SSID(i).c_str(),
                         WiFi.RSSI(i),
                         (WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? "[OPEN]" : "[SECURED]");

            if (WiFi.RSSI(i) > strongestRSSI) {
                strongestRSSI = WiFi.RSSI(i);
                strongestNetwork = WiFi.SSID(i);
            }
        }

        if (strongestNetwork.length() > 0) {
            Serial.printf("\n[SCAN] Strongest network: %s at %d dBm\n",
                         strongestNetwork.c_str(), strongestRSSI);
            // Use real RSSI as starting point
            currentRSSI = strongestRSSI;
            baseRSSI = strongestRSSI;
        }
        Serial.println("");
    }

    WiFi.scanDelete();
}

// =============================================================================
// UTILITY FUNCTIONS
// =============================================================================

void clearAllLEDs() {
    digitalWrite(LED_EXCELLENT, LOW);
    digitalWrite(LED_GOOD, LOW);
    digitalWrite(LED_FAIR, LOW);
    digitalWrite(LED_POOR, LOW);
    digitalWrite(LED_TX, LOW);
    digitalWrite(LED_ACK, LOW);
}

void flashAllLEDs(int times, int delayMs) {
    for (int i = 0; i < times; i++) {
        digitalWrite(LED_EXCELLENT, HIGH);
        digitalWrite(LED_GOOD, HIGH);
        digitalWrite(LED_FAIR, HIGH);
        digitalWrite(LED_POOR, HIGH);
        delay(delayMs);
        digitalWrite(LED_EXCELLENT, LOW);
        digitalWrite(LED_GOOD, LOW);
        digitalWrite(LED_FAIR, LOW);
        digitalWrite(LED_POOR, LOW);
        delay(delayMs);
    }
}

void startupSequence() {
    // Sequential LED test
    int leds[] = {LED_EXCELLENT, LED_GOOD, LED_FAIR, LED_POOR, LED_TX, LED_ACK};

    for (int i = 0; i < 6; i++) {
        digitalWrite(leds[i], HIGH);
        delay(150);
        digitalWrite(leds[i], LOW);
    }

    // All on briefly
    for (int i = 0; i < 6; i++) {
        digitalWrite(leds[i], HIGH);
    }
    delay(300);
    clearAllLEDs();
}

void printWelcome() {
    Serial.println("\n");
    Serial.println("================================================================");
    Serial.println("     WIRELESS COMMUNICATION FUNDAMENTALS LAB                    ");
    Serial.println("     ESP32 Wi-Fi RSSI & Packet Transmission Simulator           ");
    Serial.println("================================================================");
    Serial.println("                                                                ");
    Serial.println("  This lab demonstrates key wireless propagation concepts:      ");
    Serial.println("                                                                ");
    Serial.println("  1. RSSI Measurement     - Signal strength in dBm             ");
    Serial.println("  2. Path Loss            - Signal weakens with distance       ");
    Serial.println("  3. Fading               - Random signal variations           ");
    Serial.println("  4. Interference         - External signal disruption         ");
    Serial.println("  5. Packet Loss          - Failed transmissions               ");
    Serial.println("  6. Retransmissions      - Recovery from packet loss          ");
    Serial.println("  7. Link Budget          - Margin above minimum signal        ");
    Serial.println("                                                                ");
    Serial.println("================================================================");
    Serial.println("  LED Indicators:                                               ");
    Serial.println("    GREEN  = Excellent signal (> -50 dBm)                       ");
    Serial.println("    YELLOW = Good signal      (-50 to -60 dBm)                  ");
    Serial.println("    ORANGE = Fair signal      (-60 to -70 dBm)                  ");
    Serial.println("    RED    = Poor signal      (< -70 dBm)                       ");
    Serial.println("    BLUE   = Transmitting packet                                ");
    Serial.println("    WHITE  = ACK received                                       ");
    Serial.println("                                                                ");
    Serial.println("================================================================");
    Serial.println("  Controls:                                                     ");
    Serial.println("    Button 1 = Simulate interference burst (3 seconds)         ");
    Serial.println("    Button 2 = Increase simulated distance                     ");
    Serial.println("    Button 3 = Send test packet                                ");
    Serial.println("    Button 3 (hold 2s) = Reset all statistics                  ");
    Serial.println("                                                                ");
    Serial.println("================================================================");
    Serial.println("\n");
}

78.6.6 Challenge Exercises

After running the basic lab, try these challenges to deepen your understanding:

CautionChallenge 1: Link Budget Analysis

Objective: Observe how distance affects packet loss rate.

Steps: 1. Reset statistics (long-press Button 3) 2. At 10m distance, send 20 packets and record packet loss rate 3. Increase distance to 50m (press Button 2 multiple times) 4. Send another 20 packets and record the new packet loss rate 5. Compare the two rates

Questions to Answer: - At what distance does packet loss become significant? - How does this relate to the link budget concept? - What RSSI threshold correlates with unreliable communication?

CautionChallenge 2: Interference Impact

Objective: Measure the effect of interference on communication reliability.

Steps: 1. Reset statistics 2. Send 10 packets without interference, record success rate 3. Reset statistics 4. Trigger interference (Button 1), then immediately send 10 packets 5. Compare the packet loss rates

Questions to Answer: - How much does interference degrade packet delivery? - Why is fading margin important in real deployments? - How do retransmissions help recover from interference?

CautionChallenge 3: Retransmission Analysis

Objective: Understand adaptive retransmission behavior.

Steps: 1. Set distance to maximum (100m) 2. Enable interference 3. Send 15 packets and observe retransmission patterns 4. Note the average retries per successful packet

Questions to Answer: - How many retries are typically needed at poor signal levels? - What is the trade-off between reliability and latency? - When should you give up on retransmissions?


78.6.7 Expected Outcomes

After completing this lab, you should observe and understand:

NoteKey Observations

1. RSSI and Signal Quality Relationship - Green LED (> -50 dBm): Nearly 100% packet success - Yellow LED (-50 to -60 dBm): > 95% packet success - Orange LED (-60 to -70 dBm): ~90% packet success - Red LED (< -70 dBm): Significant packet loss begins

2. Distance vs Signal Strength - Each distance doubling reduces RSSI by approximately 6-9 dB (depending on path loss exponent) - At 100m simulated distance, signal is typically in the โ€œfairโ€ to โ€œpoorโ€ range - This demonstrates the inverse-square law in action

3. Interference Effects - Active interference reduces RSSI by 25 dB (as configured) - Even excellent signals can become unusable during interference bursts - This shows why spectrum analysis and channel selection matter

4. Retransmission Behavior - Retries increase significantly below -70 dBm RSSI - Maximum retries (3) often exhausted at very poor signal levels - Average retries/packet provides a practical link quality metric

5. Link Budget Implications - Link margin = Current RSSI - Minimum usable RSSI (-90 dBm) - Margins > 20 dB provide reliable operation - Margins < 10 dB result in frequent packet loss

TipReal-World Applications

The concepts demonstrated in this lab directly apply to:

Lab Concept Real-World Application
RSSI thresholds Wi-Fi access point placement, coverage planning
Path loss model Predicting wireless range before deployment
Interference simulation Understanding 2.4 GHz band congestion
Packet retransmission Protocol reliability mechanisms (TCP, LoRaWAN)
Link budget analysis Antenna selection, transmit power configuration

Industry Best Practice: Always deploy with at least 15-20 dB link margin to account for fading, interference, and environmental changes over time.


78.7 Summary

Concept Key Points
Indoor Challenges Walls (3-15 dB loss each), metal structures, furniture absorption
Outdoor Challenges Distance, weather, interference, regulatory limits
Antenna Selection 3 dB gain = 2x range; omnidirectional vs directional trade-offs
Key Trade-offs Sub-GHz vs 2.4 GHz, power vs battery, margin vs cost
Lab Findings RSSI > -70 dBm for reliability, 15-20 dB margin recommended

78.8 Whatโ€™s Next

With wireless propagation fundamentals understood, youโ€™re ready for:

NoteRelated Chapters