@smartnet360/svelte-components 0.0.102 → 0.0.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/apps/antenna-pattern/index.d.ts +1 -0
  2. package/dist/apps/antenna-pattern/index.js +1 -0
  3. package/dist/apps/antenna-pattern/utils/load-static-antennas.d.ts +17 -0
  4. package/dist/apps/antenna-pattern/utils/load-static-antennas.js +83 -0
  5. package/dist/apps/site-check/SiteCheck.svelte +13 -81
  6. package/dist/apps/site-check/SiteCheckControls.svelte +0 -7
  7. package/dist/apps/site-check/helper.js +0 -33
  8. package/dist/apps/site-check/transforms.js +15 -65
  9. package/dist/core/CellTable/CellTable.svelte +456 -0
  10. package/dist/core/CellTable/CellTable.svelte.d.ts +27 -0
  11. package/dist/core/CellTable/CellTablePanel.svelte +211 -0
  12. package/dist/core/CellTable/CellTablePanel.svelte.d.ts +49 -0
  13. package/dist/core/CellTable/CellTableToolbar.svelte +218 -0
  14. package/dist/core/CellTable/CellTableToolbar.svelte.d.ts +32 -0
  15. package/dist/core/CellTable/column-config.d.ts +63 -0
  16. package/dist/core/CellTable/column-config.js +465 -0
  17. package/dist/core/CellTable/index.d.ts +10 -0
  18. package/dist/core/CellTable/index.js +11 -0
  19. package/dist/core/CellTable/types.d.ts +166 -0
  20. package/dist/core/CellTable/types.js +6 -0
  21. package/dist/core/Charts/ChartCard.svelte +118 -31
  22. package/dist/core/Charts/ChartCard.svelte.d.ts +2 -0
  23. package/dist/core/Charts/ChartComponent.svelte +8 -31
  24. package/dist/core/Charts/data-processor.js +1 -19
  25. package/dist/core/CoverageMap/ai/AITools.d.ts +117 -0
  26. package/dist/core/CoverageMap/ai/AITools.js +380 -0
  27. package/dist/core/CoverageMap/core/CoverageCalculator.d.ts +138 -0
  28. package/dist/core/CoverageMap/core/CoverageCalculator.js +375 -0
  29. package/dist/core/CoverageMap/core/GridCalculator.d.ts +115 -0
  30. package/dist/core/CoverageMap/core/GridCalculator.js +484 -0
  31. package/dist/core/CoverageMap/core/PathLossModels.d.ts +253 -0
  32. package/dist/core/CoverageMap/core/PathLossModels.js +380 -0
  33. package/dist/core/CoverageMap/core/SignalProcessor.d.ts +288 -0
  34. package/dist/core/CoverageMap/core/SignalProcessor.js +424 -0
  35. package/dist/core/CoverageMap/data/AntennaStore.d.ts +165 -0
  36. package/dist/core/CoverageMap/data/AntennaStore.js +327 -0
  37. package/dist/core/CoverageMap/data/SiteStore.d.ts +155 -0
  38. package/dist/core/CoverageMap/data/SiteStore.js +355 -0
  39. package/dist/core/CoverageMap/index.d.ts +74 -0
  40. package/dist/core/CoverageMap/index.js +103 -0
  41. package/dist/core/CoverageMap/types.d.ts +252 -0
  42. package/dist/core/CoverageMap/types.js +7 -0
  43. package/dist/core/CoverageMap/utils/geoUtils.d.ts +223 -0
  44. package/dist/core/CoverageMap/utils/geoUtils.js +374 -0
  45. package/dist/core/CoverageMap/utils/rfUtils.d.ts +329 -0
  46. package/dist/core/CoverageMap/utils/rfUtils.js +434 -0
  47. package/dist/core/CoverageMap/visualization/ColorSchemes.d.ts +149 -0
  48. package/dist/core/CoverageMap/visualization/ColorSchemes.js +377 -0
  49. package/dist/core/TreeView/index.d.ts +4 -4
  50. package/dist/core/TreeView/index.js +5 -5
  51. package/dist/core/TreeView/tree-utils.d.ts +12 -0
  52. package/dist/core/TreeView/tree-utils.js +115 -6
  53. package/dist/core/TreeView/tree.store.svelte.d.ts +94 -0
  54. package/dist/core/TreeView/tree.store.svelte.js +274 -0
  55. package/dist/core/index.d.ts +1 -0
  56. package/dist/core/index.js +2 -0
  57. package/dist/map-v2/features/cells/controls/CellFilterControl.svelte +16 -27
  58. package/dist/map-v2/features/repeaters/controls/RepeaterFilterControl.svelte +33 -42
  59. package/dist/map-v2/features/sites/controls/SiteFilterControl.svelte +12 -19
  60. package/dist/map-v3/core/components/Map.svelte +4 -0
  61. package/dist/map-v3/core/stores/map.store.svelte.js +2 -0
  62. package/dist/map-v3/features/cells/components/CellFilterControl.svelte +24 -30
  63. package/dist/map-v3/features/coverage/index.d.ts +12 -0
  64. package/dist/map-v3/features/coverage/index.js +16 -0
  65. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte +198 -0
  66. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte.d.ts +10 -0
  67. package/dist/map-v3/features/coverage/logic/coloring.d.ts +28 -0
  68. package/dist/map-v3/features/coverage/logic/coloring.js +77 -0
  69. package/dist/map-v3/features/coverage/logic/geometry.d.ts +33 -0
  70. package/dist/map-v3/features/coverage/logic/geometry.js +112 -0
  71. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.d.ts +46 -0
  72. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.js +95 -0
  73. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.d.ts +33 -0
  74. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.js +90 -0
  75. package/dist/map-v3/features/coverage/types.d.ts +52 -0
  76. package/dist/map-v3/features/coverage/types.js +7 -0
  77. package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte +14 -20
  78. package/dist/map-v3/features/sites/components/SiteFilterControl.svelte +23 -33
  79. package/dist/map-v3/index.d.ts +4 -0
  80. package/dist/map-v3/index.js +5 -0
  81. package/package.json +4 -3
  82. package/dist/apps/site-check/transforms-old.d.ts +0 -56
  83. package/dist/apps/site-check/transforms-old.js +0 -273
  84. package/dist/core/TreeView/tree.store.d.ts +0 -10
  85. package/dist/core/TreeView/tree.store.js +0 -320
@@ -0,0 +1,434 @@
1
+ /**
2
+ * RF Utility Functions
3
+ *
4
+ * This module provides heavily commented RF (Radio Frequency) calculations:
5
+ * - dB arithmetic (addition, subtraction, conversion)
6
+ * - EIRP (Effective Isotropic Radiated Power) calculations
7
+ * - Link budget calculations
8
+ * - Power conversions (dBm, watts, dBd, dBi)
9
+ *
10
+ * RF calculations are done in dB (decibel) domain because:
11
+ * 1. Multiplication becomes addition (easier math)
12
+ * 2. Large dynamic range (can represent 1mW to 1MW easily)
13
+ * 3. Industry standard
14
+ */
15
+ // ============================================================================
16
+ // CONSTANTS
17
+ // ============================================================================
18
+ /**
19
+ * Conversion factor between dBd and dBi
20
+ *
21
+ * dBd = gain relative to dipole antenna
22
+ * dBi = gain relative to isotropic antenna (theoretical point source)
23
+ *
24
+ * Relationship: dBi = dBd + 2.15
25
+ *
26
+ * Example:
27
+ * A 10 dBd antenna = 12.15 dBi
28
+ * Most commercial specs use dBd, calculations often need dBi
29
+ */
30
+ export const DBD_TO_DBI = 2.15;
31
+ // ============================================================================
32
+ // dB CONVERSIONS AND ARITHMETIC
33
+ // ============================================================================
34
+ /**
35
+ * Convert dBm to watts (linear power)
36
+ *
37
+ * dBm is power relative to 1 milliwatt on a logarithmic scale:
38
+ * P_dBm = 10 × log₁₀(P_mW / 1mW)
39
+ *
40
+ * To convert back to watts:
41
+ * P_watts = 10^(P_dBm / 10) / 1000
42
+ *
43
+ * Common values to remember:
44
+ * 0 dBm = 1 mW = 0.001 W
45
+ * 10 dBm = 10 mW = 0.01 W
46
+ * 20 dBm = 100 mW = 0.1 W
47
+ * 30 dBm = 1 W
48
+ * 40 dBm = 10 W
49
+ * 43 dBm = 20 W (typical cellular base station)
50
+ *
51
+ * @param dBm - Power in dBm
52
+ * @returns Power in watts
53
+ *
54
+ * @example
55
+ * const power = dBmToWatts(43); // Typical cell site TX power
56
+ * // Returns: 19.95 watts (≈ 20W)
57
+ */
58
+ export function dBmToWatts(dBm) {
59
+ // Step 1: Convert dBm to milliwatts using inverse log
60
+ const milliwatts = Math.pow(10, dBm / 10);
61
+ // Step 2: Convert milliwatts to watts
62
+ const watts = milliwatts / 1000;
63
+ return watts;
64
+ }
65
+ /**
66
+ * Convert watts to dBm
67
+ *
68
+ * @param watts - Power in watts
69
+ * @returns Power in dBm
70
+ *
71
+ * @example
72
+ * const dBm = wattsTodBm(20); // 20 watt transmitter
73
+ * // Returns: 43.01 dBm
74
+ */
75
+ export function wattsTodBm(watts) {
76
+ // Convert watts to milliwatts
77
+ const milliwatts = watts * 1000;
78
+ // Convert to dBm using logarithm
79
+ const dBm = 10 * Math.log10(milliwatts);
80
+ return dBm;
81
+ }
82
+ /**
83
+ * Convert dBd to dBi
84
+ *
85
+ * dBd = gain relative to half-wave dipole antenna
86
+ * dBi = gain relative to isotropic radiator
87
+ *
88
+ * An isotropic antenna radiates equally in all directions (theoretical).
89
+ * A dipole has slight directionality, giving it 2.15 dB gain over isotropic.
90
+ *
91
+ * Therefore: dBi = dBd + 2.15
92
+ *
93
+ * @param dBd - Gain in dBd
94
+ * @returns Gain in dBi
95
+ */
96
+ export function dBdTodBi(dBd) {
97
+ return dBd + DBD_TO_DBI;
98
+ }
99
+ /**
100
+ * Convert dBi to dBd
101
+ *
102
+ * @param dBi - Gain in dBi
103
+ * @returns Gain in dBd
104
+ */
105
+ export function dBiTodBd(dBi) {
106
+ return dBi - DBD_TO_DBI;
107
+ }
108
+ /**
109
+ * Add two power values in dB domain
110
+ *
111
+ * IMPORTANT: You cannot just add dB values to combine powers!
112
+ *
113
+ * Correct method:
114
+ * 1. Convert both dB values to linear (watts)
115
+ * 2. Add the linear values
116
+ * 3. Convert back to dB
117
+ *
118
+ * Formula:
119
+ * P_total_dB = 10 × log₁₀(10^(P1_dB/10) + 10^(P2_dB/10))
120
+ *
121
+ * Special cases:
122
+ * - Two equal powers: P_total = P1 + 3 dB (doubling power = +3 dB)
123
+ * - Powers differ by >10 dB: P_total ≈ larger value (small contribution ignored)
124
+ *
125
+ * @param dB1 - First power in dB
126
+ * @param dB2 - Second power in dB
127
+ * @returns Combined power in dB
128
+ *
129
+ * @example
130
+ * const combined = addPowersdB(20, 20); // Two 20 dBm sources
131
+ * // Returns: 23 dBm (not 40!)
132
+ */
133
+ export function addPowersdB(dB1, dB2) {
134
+ // Convert to linear scale
135
+ const linear1 = Math.pow(10, dB1 / 10);
136
+ const linear2 = Math.pow(10, dB2 / 10);
137
+ // Add in linear domain
138
+ const totalLinear = linear1 + linear2;
139
+ // Convert back to dB
140
+ const totaldB = 10 * Math.log10(totalLinear);
141
+ return totaldB;
142
+ }
143
+ /**
144
+ * Subtract two power values in dB domain (for interference calculations)
145
+ *
146
+ * This calculates the power remaining after subtracting one power from another.
147
+ *
148
+ * Formula:
149
+ * P_diff_dB = 10 × log₁₀(10^(P1_dB/10) - 10^(P2_dB/10))
150
+ *
151
+ * Note: Returns -Infinity if P2 >= P1 (can't subtract more than you have)
152
+ *
153
+ * @param dB1 - First power in dB (larger)
154
+ * @param dB2 - Second power in dB (smaller)
155
+ * @returns Difference in dB
156
+ */
157
+ export function subtractPowersdB(dB1, dB2) {
158
+ const linear1 = Math.pow(10, dB1 / 10);
159
+ const linear2 = Math.pow(10, dB2 / 10);
160
+ if (linear1 <= linear2) {
161
+ return -Infinity; // Can't subtract more than we have
162
+ }
163
+ const diffLinear = linear1 - linear2;
164
+ const diffdB = 10 * Math.log10(diffLinear);
165
+ return diffdB;
166
+ }
167
+ // ============================================================================
168
+ // EIRP CALCULATIONS
169
+ // ============================================================================
170
+ /**
171
+ * Calculate EIRP (Effective Isotropic Radiated Power)
172
+ *
173
+ * EIRP is the apparent power radiated by an antenna in the direction of peak gain.
174
+ * It combines:
175
+ * 1. Transmitter power
176
+ * 2. Cable/connector losses (reduces power)
177
+ * 3. Antenna gain (increases power in specific direction)
178
+ *
179
+ * Formula (in dB domain - simple addition!):
180
+ * EIRP = P_tx + G_antenna - L_cable
181
+ *
182
+ * Where:
183
+ * - P_tx = Transmit power (dBm)
184
+ * - G_antenna = Antenna gain (dBi) - must be in dBi, not dBd!
185
+ * - L_cable = Cable and connector losses (dB) - positive value
186
+ *
187
+ * In linear domain, this would be multiplication/division:
188
+ * EIRP = P_tx × G_antenna / L_cable
189
+ *
190
+ * Why EIRP matters:
191
+ * - Determines maximum signal strength at receiver
192
+ * - Regulatory limits often specified as EIRP
193
+ * - Used in link budget calculations
194
+ *
195
+ * Typical values:
196
+ * - Small cell: 30-40 dBm EIRP
197
+ * - Macro cell: 50-65 dBm EIRP
198
+ * - Microwave link: 40-50 dBm EIRP
199
+ *
200
+ * @param txPowerdBm - Transmit power in dBm
201
+ * @param antennaGaindBi - Antenna gain in dBi (not dBd!)
202
+ * @param cableLossdB - Cable and connector losses in dB (default: 0.5 dB)
203
+ * @returns EIRP in dBm
204
+ *
205
+ * @example
206
+ * const eirp = calculateEIRP(43, 15, 1);
207
+ * // 43 dBm TX power (20W)
208
+ * // + 15 dBi antenna gain
209
+ * // - 1 dB cable loss
210
+ * // = 57 dBm EIRP (500W equivalent isotropic)
211
+ */
212
+ export function calculateEIRP(txPowerdBm, antennaGaindBi, cableLossdB = 0.5) {
213
+ // In dB domain, this is simple addition/subtraction
214
+ const eirp = txPowerdBm + antennaGaindBi - cableLossdB;
215
+ return eirp;
216
+ }
217
+ /**
218
+ * Calculate effective EIRP in a specific direction
219
+ *
220
+ * Antennas don't radiate equally in all directions - they have patterns.
221
+ * This calculates the EIRP in a specific direction by:
222
+ * 1. Starting with maximum EIRP (boresight direction)
223
+ * 2. Subtracting the pattern attenuation for the given direction
224
+ *
225
+ * Formula:
226
+ * EIRP_direction = EIRP_max - Attenuation(angle)
227
+ *
228
+ * Where:
229
+ * - EIRP_max = Maximum EIRP (boresight)
230
+ * - Attenuation(angle) = Pattern loss at specific angle (dB)
231
+ *
232
+ * Example:
233
+ * - EIRP_max = 60 dBm
234
+ * - At 30° off boresight, pattern shows -3 dB
235
+ * - EIRP at 30° = 60 - 3 = 57 dBm
236
+ *
237
+ * @param maxEIRP - Maximum EIRP (dBm)
238
+ * @param patternAttenuation - Pattern attenuation at angle (dB, positive value)
239
+ * @returns Effective EIRP in direction (dBm)
240
+ */
241
+ export function calculateEffectiveEIRP(maxEIRP, patternAttenuation) {
242
+ return maxEIRP - patternAttenuation;
243
+ }
244
+ // ============================================================================
245
+ // LINK BUDGET CALCULATIONS
246
+ // ============================================================================
247
+ /**
248
+ * Calculate received signal strength
249
+ *
250
+ * This is the fundamental equation for RF coverage prediction:
251
+ *
252
+ * P_received = EIRP - PathLoss + RX_Gain - RX_Losses
253
+ *
254
+ * Where (all in dB):
255
+ * - EIRP = Effective Isotropic Radiated Power (dBm)
256
+ * - PathLoss = Free space or propagation loss (dB) - positive value
257
+ * - RX_Gain = Receiver antenna gain (dBi) - usually small for mobiles
258
+ * - RX_Losses = Receiver losses, body loss, etc. (dB) - positive value
259
+ *
260
+ * For mobile devices:
261
+ * - RX_Gain ≈ 0 dBi (omnidirectional antenna)
262
+ * - RX_Losses ≈ 3 dB (body loss, hand proximity)
263
+ * - Net effect: -3 dB
264
+ *
265
+ * Interpretation:
266
+ * - P_received > -70 dBm: Excellent signal
267
+ * - P_received > -85 dBm: Good signal
268
+ * - P_received > -95 dBm: Fair signal (data services OK)
269
+ * - P_received > -105 dBm: Poor signal (voice calls only)
270
+ * - P_received < -105 dBm: No service
271
+ *
272
+ * @param eirp - Effective radiated power in direction (dBm)
273
+ * @param pathLoss - Path loss in dB (positive value)
274
+ * @param rxGain - Receiver antenna gain in dBi (default: 0)
275
+ * @param rxLosses - Receiver losses in dB (default: 3)
276
+ * @returns Received signal strength in dBm
277
+ *
278
+ * @example
279
+ * const rxPower = calculateReceivedPower(57, 110, 0, 3);
280
+ * // 57 dBm EIRP
281
+ * // - 110 dB path loss (1 km at 700 MHz)
282
+ * // + 0 dBi receiver gain
283
+ * // - 3 dB receiver losses
284
+ * // = -56 dBm (excellent signal)
285
+ */
286
+ export function calculateReceivedPower(eirp, pathLoss, rxGain = 0, rxLosses = 3) {
287
+ // Link budget equation in dB domain
288
+ const receivedPower = eirp - pathLoss + rxGain - rxLosses;
289
+ return receivedPower;
290
+ }
291
+ /**
292
+ * Calculate maximum range for a given signal threshold
293
+ *
294
+ * This inverts the link budget equation to find the distance where
295
+ * received power equals a specific threshold (e.g., -95 dBm).
296
+ *
297
+ * Starting from:
298
+ * P_rx = EIRP - PathLoss(d)
299
+ *
300
+ * Rearranging:
301
+ * PathLoss(d) = EIRP - P_rx_threshold
302
+ *
303
+ * Then using path loss model (e.g., FSPL):
304
+ * FSPL = 32.45 + 20log₁₀(d_km) + 20log₁₀(f_MHz)
305
+ *
306
+ * Solving for d:
307
+ * d_km = 10^((FSPL - 32.45 - 20log₁₀(f_MHz)) / 20)
308
+ *
309
+ * This gives us the theoretical maximum range in ideal conditions.
310
+ *
311
+ * @param eirp - Effective radiated power (dBm)
312
+ * @param frequencyMHz - Frequency in MHz
313
+ * @param threshold - Minimum received power (dBm), e.g., -95
314
+ * @param rxGain - Receiver gain (dBi), default: 0
315
+ * @param rxLosses - Receiver losses (dB), default: 3
316
+ * @returns Maximum range in kilometers
317
+ */
318
+ export function calculateMaxRange(eirp, frequencyMHz, threshold, rxGain = 0, rxLosses = 3) {
319
+ // Calculate allowed path loss
320
+ // This is how much loss we can tolerate before signal drops below threshold
321
+ const allowedPathLoss = eirp - threshold + rxGain - rxLosses;
322
+ // Use FSPL model: FSPL = 32.45 + 20log₁₀(d_km) + 20log₁₀(f_MHz)
323
+ // Solve for d_km:
324
+ const frequencyTerm = 20 * Math.log10(frequencyMHz);
325
+ const exponent = (allowedPathLoss - 32.45 - frequencyTerm) / 20;
326
+ const maxRangeKm = Math.pow(10, exponent);
327
+ return maxRangeKm;
328
+ }
329
+ // ============================================================================
330
+ // ANTENNA PATTERN UTILITIES
331
+ // ============================================================================
332
+ /**
333
+ * Convert antenna pattern attenuation to gain
334
+ *
335
+ * Antenna pattern files typically store attenuation values:
336
+ * - 0 dB = maximum gain (boresight direction)
337
+ * - Positive values = attenuation (less gain)
338
+ * - Example: 3 dB attenuation = 3 dB below maximum
339
+ *
340
+ * To get actual gain in a direction:
341
+ * Gain(angle) = MaxGain - Attenuation(angle)
342
+ *
343
+ * @param maxGain - Maximum antenna gain (dBi or dBd)
344
+ * @param attenuation - Pattern attenuation at angle (dB)
345
+ * @returns Effective gain at angle
346
+ *
347
+ * @example
348
+ * const gain = attenuationToGain(15, 3);
349
+ * // 15 dBi max gain
350
+ * // - 3 dB attenuation at 30°
351
+ * // = 12 dBi gain at 30°
352
+ */
353
+ export function attenuationToGain(maxGain, attenuation) {
354
+ return maxGain - attenuation;
355
+ }
356
+ /**
357
+ * Interpolate antenna pattern value for non-integer angles
358
+ *
359
+ * Antenna patterns typically have 360 samples (one per degree).
360
+ * For angles between samples, use linear interpolation.
361
+ *
362
+ * @param pattern - Array of 360 pattern values
363
+ * @param angle - Angle in degrees (can be non-integer)
364
+ * @returns Interpolated pattern value
365
+ */
366
+ export function interpolatePattern(pattern, angle) {
367
+ // Normalize angle to 0-360 range
368
+ angle = ((angle % 360) + 360) % 360;
369
+ // Get floor and ceiling indices
370
+ const idx1 = Math.floor(angle);
371
+ const idx2 = Math.ceil(angle) % 360;
372
+ // If angle is integer, return exact value
373
+ if (idx1 === idx2) {
374
+ return pattern[idx1];
375
+ }
376
+ // Linear interpolation
377
+ const fraction = angle - idx1;
378
+ const value1 = pattern[idx1];
379
+ const value2 = pattern[idx2];
380
+ return value1 + (value2 - value1) * fraction;
381
+ }
382
+ // ============================================================================
383
+ // UTILITY FUNCTIONS
384
+ // ============================================================================
385
+ /**
386
+ * Classify signal quality based on received power
387
+ *
388
+ * @param rssi - Received signal strength in dBm
389
+ * @returns Quality category
390
+ */
391
+ export function classifySignalQuality(rssi) {
392
+ if (rssi >= -70)
393
+ return 'excellent';
394
+ if (rssi >= -85)
395
+ return 'good';
396
+ if (rssi >= -95)
397
+ return 'fair';
398
+ if (rssi >= -105)
399
+ return 'poor';
400
+ return 'no-signal';
401
+ }
402
+ /**
403
+ * Calculate signal-to-noise ratio (SNR)
404
+ *
405
+ * SNR = Signal Power - Noise Power (both in dBm)
406
+ *
407
+ * Typical noise floor: -100 to -120 dBm depending on bandwidth
408
+ *
409
+ * @param signalPower - Signal power in dBm
410
+ * @param noisePower - Noise power in dBm
411
+ * @returns SNR in dB
412
+ */
413
+ export function calculateSNR(signalPower, noisePower) {
414
+ return signalPower - noisePower;
415
+ }
416
+ /**
417
+ * Calculate thermal noise floor
418
+ *
419
+ * Formula: N = -174 + 10log₁₀(BW) + NF
420
+ *
421
+ * Where:
422
+ * - -174 dBm/Hz is thermal noise density at room temperature
423
+ * - BW is bandwidth in Hz
424
+ * - NF is receiver noise figure in dB (typically 5-9 dB)
425
+ *
426
+ * @param bandwidthHz - Signal bandwidth in Hz
427
+ * @param noiseFigure - Receiver noise figure in dB (default: 7)
428
+ * @returns Noise floor in dBm
429
+ */
430
+ export function calculateNoiseFloor(bandwidthHz, noiseFigure = 7) {
431
+ const thermalNoise = -174; // dBm/Hz
432
+ const bandwidthTerm = 10 * Math.log10(bandwidthHz);
433
+ return thermalNoise + bandwidthTerm + noiseFigure;
434
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Color Schemes
3
+ *
4
+ * This module defines color schemes for coverage visualization.
5
+ * Supports multiple visualization styles:
6
+ * - Heatmap: Gradient from strong to weak signal
7
+ * - Categorical: Discrete quality levels
8
+ * - Single color: Opacity-based (for sector identification)
9
+ *
10
+ * All colors designed to be:
11
+ * - Colorblind-friendly (where possible)
12
+ * - Print-friendly
13
+ * - Intuitive (red = strong, blue = weak for heatmap)
14
+ */
15
+ import type { SignalQuality, SignalThresholds } from '../types';
16
+ export interface ColorStop {
17
+ value: number;
18
+ color: string;
19
+ }
20
+ export interface ColorScheme {
21
+ name: string;
22
+ description: string;
23
+ stops: ColorStop[];
24
+ noSignalColor: string;
25
+ }
26
+ /**
27
+ * Heatmap - Red to Blue gradient
28
+ *
29
+ * Classic heatmap where:
30
+ * - Red = Excellent signal (hot)
31
+ * - Orange/Yellow = Good signal (warm)
32
+ * - Green = Fair signal (cool)
33
+ * - Blue = Poor signal (cold)
34
+ * - Gray = No signal
35
+ *
36
+ * This is intuitive for most users.
37
+ */
38
+ export declare const HEATMAP_RED_BLUE: ColorScheme;
39
+ /**
40
+ * Heatmap - Green to Red (inverted)
41
+ *
42
+ * Alternative where:
43
+ * - Green = Excellent (good status)
44
+ * - Yellow = Fair (warning)
45
+ * - Red = Poor (problem)
46
+ *
47
+ * More intuitive for traffic light metaphor.
48
+ */
49
+ export declare const HEATMAP_GREEN_RED: ColorScheme;
50
+ /**
51
+ * Categorical - Discrete quality levels
52
+ *
53
+ * Uses distinct colors for each quality level.
54
+ * No gradients - clear boundaries.
55
+ * Good for presentations and reports.
56
+ */
57
+ export declare const CATEGORICAL: ColorScheme;
58
+ /**
59
+ * Viridis-inspired (colorblind-friendly)
60
+ *
61
+ * Based on matplotlib's viridis colormap.
62
+ * Optimized for colorblind users and grayscale printing.
63
+ */
64
+ export declare const VIRIDIS: ColorScheme;
65
+ /**
66
+ * Plasma-inspired (high contrast)
67
+ *
68
+ * High contrast colormap for visibility.
69
+ */
70
+ export declare const PLASMA: ColorScheme;
71
+ /**
72
+ * All available color schemes
73
+ */
74
+ export declare const COLOR_SCHEMES: Record<string, ColorScheme>;
75
+ /**
76
+ * Default color scheme
77
+ */
78
+ export declare const DEFAULT_COLOR_SCHEME: ColorScheme;
79
+ /**
80
+ * Interpolate color for a specific signal strength
81
+ *
82
+ * Uses linear interpolation between color stops to create
83
+ * smooth gradients.
84
+ *
85
+ * Process:
86
+ * 1. Find two nearest color stops
87
+ * 2. Calculate interpolation factor
88
+ * 3. Interpolate RGB components
89
+ * 4. Convert back to hex
90
+ *
91
+ * @param signalDbm - Signal strength in dBm
92
+ * @param scheme - Color scheme to use
93
+ * @returns Hex color string
94
+ *
95
+ * @example
96
+ * const color = interpolateColor(-75, HEATMAP_RED_BLUE);
97
+ * // Returns color between -70 (orange-red) and -80 (orange)
98
+ * // e.g., "#FF7400"
99
+ */
100
+ export declare function interpolateColor(signalDbm: number, scheme: ColorScheme): string;
101
+ /**
102
+ * Get color for categorical quality level
103
+ *
104
+ * Returns discrete color based on quality level without interpolation.
105
+ *
106
+ * @param quality - Signal quality level
107
+ * @param scheme - Color scheme (optional, defaults to categorical)
108
+ * @returns Hex color string
109
+ */
110
+ export declare function getCategoricalColor(quality: SignalQuality, scheme?: ColorScheme): string;
111
+ /**
112
+ * Get color based on signal thresholds
113
+ *
114
+ * Convenience function that combines threshold checking and coloring.
115
+ *
116
+ * @param signalDbm - Signal strength in dBm
117
+ * @param thresholds - Signal quality thresholds
118
+ * @param scheme - Color scheme to use
119
+ * @returns Hex color string
120
+ */
121
+ export declare function getColorForSignal(signalDbm: number, thresholds: SignalThresholds, scheme?: ColorScheme): string;
122
+ /**
123
+ * Add opacity to hex color
124
+ *
125
+ * Converts hex to rgba with specified opacity.
126
+ *
127
+ * @param hex - Hex color
128
+ * @param opacity - Opacity (0-1)
129
+ * @returns RGBA color string
130
+ *
131
+ * @example
132
+ * const semi = addOpacity("#FF0000", 0.5);
133
+ * // Returns: "rgba(255, 0, 0, 0.5)"
134
+ */
135
+ export declare function addOpacity(hex: string, opacity: number): string;
136
+ /**
137
+ * Create legend entries for a color scheme
138
+ *
139
+ * Generates legend data for UI display.
140
+ *
141
+ * @param scheme - Color scheme
142
+ * @param thresholds - Signal thresholds
143
+ * @returns Array of legend entries
144
+ */
145
+ export declare function createLegend(scheme: ColorScheme, thresholds: SignalThresholds): Array<{
146
+ label: string;
147
+ color: string;
148
+ range: string;
149
+ }>;