@mytec Phase 1 - Core UI & Manual Input, Phase 2 - RF Calculation Engine, Phase 3 - Heatmap Visualization

This commit is contained in:
2026-01-30 07:12:00 +02:00
parent 343c8e078d
commit 18a7d6de81
41 changed files with 6014 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
import type { FrequencyBand } from '@/types/index.ts';
export const COMMON_FREQUENCIES: FrequencyBand[] = [
{
value: 800,
name: 'Band 20',
range: '791-862 MHz',
type: 'LTE',
characteristics: {
range: 'long',
penetration: 'excellent',
typical: 'Rural coverage, deep building penetration',
},
},
{
value: 1800,
name: 'Band 3',
range: '1710-1880 MHz',
type: 'LTE',
characteristics: {
range: 'medium',
penetration: 'good',
typical: 'Urban/suburban, most common in Ukraine',
},
},
{
value: 1900,
name: 'Band 2',
range: '1850-1990 MHz',
type: 'LTE',
characteristics: {
range: 'medium',
penetration: 'good',
typical: 'North America, some military equipment',
},
},
{
value: 2600,
name: 'Band 7',
range: '2500-2690 MHz',
type: 'LTE',
characteristics: {
range: 'short',
penetration: 'fair',
typical: 'High capacity urban, shorter range',
},
},
{
value: 150,
name: 'VHF High',
range: '136-174 MHz',
type: 'VHF',
characteristics: {
range: 'long',
penetration: 'excellent',
typical: 'Tactical radio, emergency services',
},
},
{
value: 450,
name: 'UHF',
range: '400-470 MHz',
type: 'UHF',
characteristics: {
range: 'medium',
penetration: 'good',
typical: 'Military tactical radio, PMR446',
},
},
{
value: 3500,
name: 'Band 42/43 (n78)',
range: '3400-3800 MHz',
type: '5G',
characteristics: {
range: 'short',
penetration: 'poor',
typical: '5G NR, high bandwidth',
},
},
];
export const QUICK_FREQUENCIES = [800, 1800, 1900, 2600];
export function getFrequencyInfo(frequency: number): FrequencyBand | null {
return (
COMMON_FREQUENCIES.find((band) => Math.abs(band.value - frequency) < 50) ||
null
);
}
export function getWavelength(frequencyMHz: number): string {
const wavelengthMeters = 300 / frequencyMHz;
if (wavelengthMeters >= 1) {
return `${wavelengthMeters.toFixed(2)} m`;
}
return `${(wavelengthMeters * 100).toFixed(1)} cm`;
}

View File

@@ -0,0 +1,40 @@
export const RSRP_THRESHOLDS = {
EXCELLENT: -70,
GOOD: -85,
FAIR: -100,
POOR: -110,
WEAK: -120,
NO_SERVICE: -120,
} as const;
export type SignalQuality = 'excellent' | 'good' | 'fair' | 'poor' | 'weak' | 'no-service';
export function getSignalQuality(rsrp: number): SignalQuality {
if (rsrp >= RSRP_THRESHOLDS.EXCELLENT) return 'excellent';
if (rsrp >= RSRP_THRESHOLDS.GOOD) return 'good';
if (rsrp >= RSRP_THRESHOLDS.FAIR) return 'fair';
if (rsrp >= RSRP_THRESHOLDS.POOR) return 'poor';
if (rsrp >= RSRP_THRESHOLDS.WEAK) return 'weak';
return 'no-service';
}
export const SIGNAL_COLORS: Record<string, string> = {
excellent: '#22c55e',
good: '#84cc16',
fair: '#eab308',
poor: '#f97316',
weak: '#ef4444',
'no-service': '#6b7280',
} as const;
export function getRSRPColor(rsrp: number): string {
return SIGNAL_COLORS[getSignalQuality(rsrp)] ?? '#6b7280';
}
export const RSRP_LEGEND = [
{ label: 'Excellent', range: '> -70 dBm', color: SIGNAL_COLORS.excellent, min: -70 },
{ label: 'Good', range: '-70 to -85 dBm', color: SIGNAL_COLORS.good, min: -85 },
{ label: 'Fair', range: '-85 to -100 dBm', color: SIGNAL_COLORS.fair, min: -100 },
{ label: 'Poor', range: '-100 to -110 dBm', color: SIGNAL_COLORS.poor, min: -110 },
{ label: 'Weak', range: '-110 to -120 dBm', color: SIGNAL_COLORS.weak, min: -120 },
] as const;