SDR Frequency and Hardware Validation
Overview
The EAS Station SDR configuration UI provides comprehensive frequency and hardware validation to ensure correct receiver configuration.
Frequency Input - Already in MHz!
How It Works
The frontend already accepts frequency in MHz, not Hz. Users enter frequencies like:
- NOAA:
162.550MHz - FM:
97.9MHz - AM:
800kHz (displayed as0.800MHz)
The system automatically converts these to Hz internally before saving to the database.
Implementation Details
Frontend Fields:
receiverFrequencyInput- Visible input field accepting MHz (e.g., "162.550")receiverFrequency- Hidden field storing Hz value for backend (e.g., 162550000)
Validation Flow:
- User enters frequency in MHz in
receiverFrequencyInput - JavaScript validates via
/api/radio/validate-frequencyendpoint - Backend validates against service type constraints:
- NOAA: Must be one of 7 valid frequencies (162.400-162.550 MHz)
- FM: Must be 88.1-108.0 MHz with odd tenths (.1, .3, .5, .7, .9)
- AM: Must be 530-1700 kHz with 10 kHz spacing
- If valid, hidden field is populated with Hz value
- UI shows success/error message with formatted frequency
Code Location:
- Template:
templates/settings/radio.html(lines 1762-1802) - Validation API:
webapp/routes_settings_radio.py - Service config:
app_core/radio/service_config.py
Hardware-Specific Validation
Sample Rate Validation by Hardware
The system automatically validates sample rates based on SDR hardware capabilities.
Airspy R2 Constraints
Airspy R2 ONLY supports these exact sample rates:
- 2.5 MHz (2,500,000 Hz)
- 10 MHz (10,000,000 Hz)
The UI enforces this by:
- Detecting Airspy driver selection
- Fetching hardware capabilities from
/api/radio/capabilities/{driver} - Populating sample rate dropdown with ONLY valid rates (2.5 MHz and 10 MHz)
- Showing error if invalid rate is selected
Frontend Implementation (templates/settings/radio.html lines 1645-1703):
if (isAirspy) {
defaultRates = [2500000, 10000000]; // Only 2.5 and 10 MHz
} else {
defaultRates = [250000, 1024000, 1920000, 2048000, 2400000, 2560000];
}
Backend Validation (webapp/routes_settings_radio.py lines 282-300):
# Validate sample rate compatibility with driver
is_valid, error_msg = validate_sample_rate_for_driver(
data["driver"], sample_rate, device_args
)
if not is_valid:
return None, error_msg
Hardware Validation Function (app_core/radio/discovery.py:329):
def validate_sample_rate_for_driver(
driver: str,
sample_rate: int,
device_args: Optional[Dict[str, str]] = None
) -> tuple[bool, Optional[str]]:
"""
Validate sample rate against hardware capabilities.
Queries actual hardware if available, falls back to known constraints.
"""
RTL-SDR
RTL-SDR supports a wider range of sample rates:
- 250 kHz - 3.2 MHz typically
- Common rates: 250 kHz, 1.024 MHz, 2.048 MHz, 2.4 MHz, 2.56 MHz
SDR++ Server / Remote
Remote SDRs support rates determined by the remote hardware.
Validation Layers
The system has three layers of validation:
Frontend UI Constraints
- Dropdown shows only valid sample rates for selected hardware
- Real-time frequency validation as user types
- Visual feedback (green checkmark for valid, red X for invalid)
Frontend API Validation
/api/radio/validate-frequency- Validates frequency against service type/api/radio/capabilities/{driver}- Gets hardware-specific constraints/api/radio/service-config/{service_type}- Gets service defaults
Backend Database Validation
_parse_receiver_payload()validates all parameters before savevalidate_sample_rate_for_driver()checks hardware compatibility- Database constraints prevent invalid data
Service Type Configuration
The system automatically configures receivers based on service type:
NOAA Weather Radio
- Modulation: NFM (Narrowband FM)
- Bandwidth: 25 kHz
- Stereo: Disabled (mono only)
- De-emphasis: 75 μs (North America)
- RBDS: Disabled
- Squelch: Enabled with carrier alarm
FM Broadcast
- Modulation: WFM (Wideband FM)
- Bandwidth: 200 kHz
- Stereo: Enabled
- De-emphasis: 75 μs (North America)
- RBDS: Enabled (Program Service, Radio Text)
- Squelch: Enabled, no alarm
AM Broadcast
- Modulation: AM
- Bandwidth: 10 kHz
- Stereo: Disabled (mono only)
- De-emphasis: Disabled (AM doesn't use it)
- RBDS: Disabled
- Squelch: Enabled with carrier alarm
Validation Error Messages
Frequency Errors
NOAA:
Invalid NOAA frequency. Valid frequencies: 162.400, 162.425, 162.450,
162.475, 162.500, 162.525, 162.550 MHz
FM:
FM frequencies must end in .1, .3, .5, .7, or .9 (e.g., 97.9)
FM frequency must be between 88.1 and 108.0 MHz
AM:
AM frequency must be between 530 and 1700 kHz with 10 kHz spacing
Sample Rate Errors
Airspy:
Airspy R2 only supports 2.5 MHz and 10 MHz sample rates.
Configured rate 2.4 MHz is invalid.
Generic:
Sample rate 5000000 Hz not supported by this hardware.
Valid rates: [list of supported rates]
User Experience Flow
Adding a Receiver
Select SDR Device
- System detects hardware and driver
- Fetches hardware capabilities
Choose Service Type
- NOAA / FM / AM button group
- System loads service-specific defaults
Enter Frequency
- User types in MHz (e.g., "162.550")
- Real-time validation shows green checkmark or red error
- Help text shows valid range for service type
Select Sample Rate
- Dropdown shows ONLY valid rates for this hardware
- Recommended rate is marked with ⭐
- Help text explains hardware constraints
Configure Advanced Options
- Gain, modulation, squelch, etc.
- Defaults populated based on service type
- Hardware constraints enforced
Save
- Backend validates all parameters
- Returns specific error if validation fails
- Success: Receiver added to fleet
API Endpoints
/api/radio/validate-frequency (POST)
Validates frequency against service type constraints.
Request:
{
"service_type": "NOAA",
"frequency": "162.550"
}
Response (valid):
{
"valid": true,
"frequency_hz": 162550000,
"frequency_display": "162.550 MHz (NOAA WX7)"
}
Response (invalid):
{
"valid": false,
"error": "Invalid NOAA frequency. Valid frequencies: ..."
}
/api/radio/capabilities/{driver} (GET)
Gets hardware-specific capabilities (sample rates, gain range, etc.).
Response:
{
"driver": "airspy",
"sample_rates": [2500000, 10000000],
"gains": {
"LNA": {"min": 0, "max": 15, "step": 1},
"MIX": {"min": 0, "max": 15, "step": 1},
"VGA": {"min": 0, "max": 15, "step": 1}
},
"frequency_range": {"min": 24000000, "max": 1800000000}
}
/api/radio/service-config/{service_type} (GET)
Gets service-specific configuration defaults.
Response:
{
"modulation_type": "NFM",
"audio_output": true,
"stereo_enabled": false,
"deemphasis_us": 75.0,
"enable_rbds": false,
"bandwidth": 25000,
"frequency_placeholder": "e.g., 162.550 for WX7",
"frequency_help": "Enter NOAA Weather Radio frequency in MHz"
}
Testing Validation
Test Valid Configurations
NOAA Weather Radio (RTL-SDR):
Service Type: NOAA
Frequency: 162.550 MHz
Sample Rate: 2.4 MHz
Driver: rtlsdr
Expected: ✅ Valid
FM Broadcast (Airspy):
Service Type: FM
Frequency: 97.9 MHz
Sample Rate: 2.5 MHz
Driver: airspy
Expected: ✅ Valid
Test Invalid Configurations
Airspy with invalid sample rate:
Service Type: NOAA
Frequency: 162.550 MHz
Sample Rate: 2.4 MHz ❌ Invalid for Airspy!
Driver: airspy
Expected: ❌ Error - "Airspy only supports 2.5 or 10 MHz"
Invalid NOAA frequency:
Service Type: NOAA
Frequency: 162.600 MHz ❌ Not a valid NOAA frequency!
Expected: ❌ Error - "Invalid NOAA frequency. Valid: 162.400-162.550"
Invalid FM frequency:
Service Type: FM
Frequency: 97.8 MHz ❌ Must be odd tenth!
Expected: ❌ Error - "FM frequencies must end in .1, .3, .5, .7, or .9"
Summary
✅ Frequency input is already in MHz - No changes needed
✅ Hardware validation is already implemented - Airspy constraints enforced
✅ Service type validation is working - NOAA/FM/AM frequency ranges checked
✅ Three-layer validation - Frontend UI + API + Backend database
✅ Clear error messages - Users know exactly what's wrong
✅ Real-time feedback - Validation as you type
The system is fully functional for frequency and hardware validation. No code changes are required.
This document is served from docs/frontend/SDR_FREQUENCY_VALIDATION.md in the EAS Station installation.