1075  LoRaWAN ADR and Duty Cycle Optimization

1075.1 Learning Objectives

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

  • Understand the Adaptive Data Rate (ADR) algorithm
  • Calculate link margins and optimal spreading factors
  • Configure ADR for different deployment scenarios
  • Understand EU and US duty cycle regulations
  • Calculate message budgets under duty cycle constraints
  • Troubleshoot ADR convergence problems

1075.2 Expert Deep Dive: Protocol Internals

1075.2.1 Adaptive Data Rate (ADR) Algorithm Implementation

For practitioners implementing LoRaWAN networks, understanding the ADR algorithm internals is crucial for optimal performance.

1075.2.2 ADR Decision Process

The network server calculates optimal spreading factor using these steps:

1. Signal Quality Measurement (Gateway -> Network Server)

For each uplink from device:
  - RSSI (Received Signal Strength Indicator): Measured in dBm
  - SNR (Signal-to-Noise Ratio): Measured in dB
  - Packet count: Last 20 uplinks tracked

2. Link Margin Calculation

Link Margin = SNR - SNR_required(SF)

Required SNR by spreading factor:
SF7:  -7.5 dB
SF8:  -10 dB
SF9:  -12.5 dB
SF10: -15 dB
SF11: -17.5 dB
SF12: -20 dB

Example:
Measured SNR = -8 dB
SF7 required: -7.5 dB
Link Margin = -8 - (-7.5) = -0.5 dB -> SF7 NOT viable

SF8 required: -10 dB
Link Margin = -8 - (-10) = +2 dB -> SF8 viable but marginal

SF9 required: -12.5 dB
Link Margin = -8 - (-12.5) = +4.5 dB -> SF9 safe

3. Optimal SF Selection

def calculate_optimal_sf(snr_measurements):
    """
    ADR algorithm to determine optimal spreading factor

    Args:
        snr_measurements: List of last 20 SNR readings (dB)

    Returns:
        Optimal SF and TX power
    """
    # Use worst-case SNR from last 20 packets (with margin)
    snr_min = min(snr_measurements)

    # Required SNR per SF (dBm)
    sf_requirements = {
        7: -7.5, 8: -10, 9: -12.5,
        10: -15, 11: -17.5, 12: -20
    }

    # Target: 10 dB link margin for reliability
    target_margin = 10

    # Find lowest SF with sufficient margin
    for sf in range(7, 13):
        required_snr = sf_requirements[sf]
        link_margin = snr_min - required_snr

        if link_margin >= target_margin:
            return sf, calculate_tx_power(link_margin)

    # If no SF works with 10 dB margin, use SF12
    return 12, max_tx_power

def calculate_tx_power(link_margin):
    """
    Reduce TX power if excessive link margin
    """
    excess_margin = link_margin - 10  # Keep 10 dB safety

    if excess_margin > 0:
        # Reduce TX power by excess margin (up to 10 dB max reduction)
        power_reduction = min(excess_margin, 10)
        return default_tx_power - power_reduction

    return default_tx_power

4. ADR Command Transmission

Network Server -> Device (via LinkADRReq MAC command):
- New Spreading Factor (SF7-SF12)
- New TX Power (0-15, maps to 2-20 dBm)
- New Channel Mask (enable/disable channels)
- NbRep (number of transmissions for redundancy)

Device acknowledges with LinkADRAns

1075.2.3 Real-World ADR Example

Scenario: Sensor initially joins network at default SF12 (conservative)

Uplink # RSSI (dBm) SNR (dB) Current SF Link Margin Network Action
1 -95 +5 SF12 +25 dB Collect data
5 -96 +4 SF12 +24 dB Collect data
10 -94 +6 SF12 +26 dB Collect data
20 -95 +5 SF12 +25 dB Command: Switch to SF9
25 -96 +4 SF9 +16.5 dB Excellent
30 -95 +5 SF9 +17.5 dB Excellent
40 -94 +6 SF9 +18.5 dB Command: Switch to SF7
45 -95 +5 SF7 +12.5 dB Good (10+ dB margin)

Result: Battery life improves by 23x (SF12 -> SF7)!

1075.2.4 ADR Limitations and Pitfalls

WarningWhen ADR Fails

1. Mobile Devices:

Problem: Device moves from gateway A (strong signal) to gateway B (weak signal)
- ADR at A: SF7 (fast, short range)
- Device moves to B: Signal degrades
- Still using SF7 -> messages lost
- Takes 20+ uplinks to readjust -> unacceptable for mobile

Solution: Disable ADR for mobile devices, use SF10-SF12

2. Interferer Appears:

Problem: New Wi-Fi access point near gateway
- Before: SNR +10 dB, SF7 optimal
- After: SNR -5 dB (interference), SF7 fails
- ADR takes 20 uplinks to detect -> 20 lost messages

Solution: Faster ADR response (reduce convergence window) or use SF9-SF10 for critical apps

3. Weather Changes:

Problem: Heavy rain increases path loss by 5-10 dB
- Clear weather: SF7 with +12 dB margin
- Heavy rain: Margin drops to +2 dB -> packet loss spikes
- ADR eventually adjusts to SF9, but 10-20 packets lost

Solution: Use higher default SF in regions with severe weather

1075.2.5 Best Practices for ADR

  1. Enable ADR for stationary devices (sensors, meters)
  2. Disable ADR for mobile devices (asset trackers, vehicles)
  3. Set ADR_ACK_LIMIT = 64 (default) for good convergence
  4. Monitor failed uplink ratio -> if >5%, ADR not working well
  5. Manually set SF for critical devices where packet loss unacceptable

1075.2.6 ADR Best Practices by Deployment Type

Deployment ADR Setting Installation Margin NbTrans Notes
Urban IoT Enabled 15 dB 2 Interference-resistant
Rural Sensors Enabled 5 dB 1 Battery-optimized
Industrial Enabled 12 dB 2 Balanced reliability
Mobile Assets Disabled N/A 1 Fixed SF9-SF10
Critical Alarms Enabled 20 dB 3 Maximum reliability

1075.3 Duty Cycle Regulations and Fair Access Policy

LoRaWAN operates in unlicensed ISM bands, subject to strict duty cycle regulations:

1075.3.1 EU Regulations (ETSI EN 300.220)

Sub-bands and Duty Cycles:

Frequency (MHz) Duty Cycle Max TX Power Usage
865.0 - 868.0 1% (36 sec/hour) 25 mW (14 dBm) G1 channels (uplink)
868.0 - 868.6 1% 25 mW G channels (uplink)
868.7 - 869.2 0.1% (3.6 sec/hour) 25 mW G2 channels (uplink)
869.4 - 869.65 10% (6 min/hour) 500 mW (27 dBm) G3 downlink (gateways)

Practical Impact:

Example: SF10, 50-byte payload, 370 ms airtime

1% duty cycle (G1 channels):
- Max airtime: 3600 sec/hour x 1% = 36 sec/hour
- Messages allowed: 36000 ms / 370 ms = 97 messages/hour
- Minimum interval: 370 ms x 100 = 37 seconds between messages

0.1% duty cycle (G2 channels):
- Max airtime: 3600 sec/hour x 0.1% = 3.6 sec/hour
- Messages allowed: 3600 ms / 370 ms = 9.7 messages/hour
- Minimum interval: 370 ms x 1000 = 370 seconds (6.2 minutes!)

1075.3.2 US Regulations (FCC Part 15)

Unlicensed ISM Band: 902-928 MHz

Parameter Limit Notes
Duty Cycle None (but Fair Access Policy applies) No explicit duty cycle
Max EIRP 4W (36 dBm) with FHSS Frequency hopping required
Dwell Time 400 ms per channel Must hop channels
Hop Channels 50+ channels LoRaWAN uses 64 or 72 channels

LoRaWAN Fair Access Policy (US):

Recommendation: Uplink duty cycle 4% or less (even though not regulated)
- Prevents network saturation
- Allows fair sharing of spectrum
- Max ~2 minutes of airtime per hour

1075.3.3 Duty Cycle Violation Consequences

CautionWhat Happens If You Violate Duty Cycle?

Regulatory: - EU: Fines up to 10,000 EUR+ per violation - FCC: Fines, equipment seizure, spectrum ban - Enforcement: Automatic monitoring systems detect violations

Network: - The Things Network: Device automatically blocked - Private networks: Self-inflicted interference, packet loss - Other users: Your transmissions cause collisions

Technical: - Module firmware enforces duty cycle (cannot bypass) - Attempted transmission queued until duty cycle resets - Confirmed messages may fail if ACK arrives during duty cycle block

1075.3.4 Calculating Message Budget

Example: Smart meter (EU 868 MHz, G1 channel, 1% duty cycle)

def calculate_max_messages(sf, payload_bytes):
    """
    Calculate maximum messages per hour under 1% duty cycle
    """
    # Airtime table for EU868, BW=125kHz (milliseconds)
    airtime_table = {
        7: {10: 41, 20: 51, 50: 72},
        8: {10: 72, 20: 92, 50: 133},
        9: {10: 144, 20: 185, 50: 247},
        10: {10: 247, 20: 329, 50: 452},
        11: {10: 454, 20: 617, 50: 865},
        12: {10: 908, 20: 1233, 50: 1745}
    }

    # Find closest payload size
    closest_payload = min([10, 20, 50], key=lambda x: abs(x - payload_bytes))
    airtime_ms = airtime_table[sf][closest_payload]

    # 1% duty cycle = 36,000 ms per hour
    duty_cycle_budget_ms = 36000

    max_messages = duty_cycle_budget_ms / airtime_ms
    min_interval_sec = (airtime_ms / 1000) * 100  # 1% = 100x wait

    return int(max_messages), min_interval_sec

# Examples:
# SF7, 20 bytes: (705 msg/hr, 5.1 sec interval)
# SF10, 50 bytes: (79 msg/hr, 45.2 sec interval)
# SF12, 50 bytes: (20 msg/hr, 174.5 sec = 2.9 min interval)

Key Insight: Higher spreading factors severely limit message frequency under duty cycle constraints. This is another reason why ADR is critical!

1075.4 Understanding Check: Class A Firmware Updates

Scenario: A municipal water utility has deployed 5,000 LoRaWAN smart meters (Class A devices) across the city. Each meter reports usage once per hour. A critical security patch requires a firmware update - the new firmware is 100 KB. The utility needs to update all meters within 2 weeks.

Think about: 1. Why is the Class A receive window architecture a problem for large file transfers? 2. How many downlink messages would each meter need to receive the full firmware? 3. What trade-offs exist between Class A, Class B, and Class C for this scenario?

The Math: - Firmware size: 100 KB = 100,000 bytes - LoRaWAN payload: ~100 bytes per message (average) - Messages needed: 100,000 / 100 = 1,000 downlink messages per meter - At 1 uplink/hour: 1,000 hours = 41 days per device - For 5,000 meters sequentially: Impossible within 2 weeks

Update Strategy Receive Windows Battery Impact Time to Update 5,000 Meters
Class A After uplink only (3 sec total) Lowest 41 days x sequential = Months
Class B Scheduled + uplink windows Medium ~1 week with coordination
Class C Always listening Highest (mains power needed) 1-2 days

Practical Takeaway: Class A is perfect for sensors sending data upward, but firmware updates require either patient sequential updates, Class B coordination, or Class C power availability.

1075.5 Summary

This chapter covered ADR and duty cycle optimization:

  • ADR Algorithm: Uses 20 uplinks to calculate optimal SF based on link margin
  • Link Margin Target: 10 dB for reliability, adjustable per deployment
  • ADR Limitations: Fails with mobile devices, sudden interference, weather changes
  • EU Duty Cycle: 1% (36 sec/hour) on main sub-bands
  • US Regulations: No duty cycle but 400ms dwell time and frequency hopping
  • Message Budget: Higher SF = fewer messages possible under duty cycle

1075.6 What’s Next

Continue to Common Pitfalls to learn about common LoRaWAN deployment mistakes and how to avoid them.

Alternative paths: - LoRaWAN Lab - Hands-on simulation exercises - Practice Exercises - Test your knowledge