@mytec: iter1.5.1 start
This commit is contained in:
229
RFCP-Iteration-1.5.1-Fixes-Boundaries.md
Normal file
229
RFCP-Iteration-1.5.1-Fixes-Boundaries.md
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
# RFCP Iteration 1.5.1: Fixes & Boundaries
|
||||||
|
|
||||||
|
**Date:** January 31, 2025
|
||||||
|
**Type:** Bugfix & Polish
|
||||||
|
**Estimated:** 2-3 hours
|
||||||
|
**Location:** `/opt/rfcp/frontend/` + `/opt/rfcp/backend/`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Goal
|
||||||
|
|
||||||
|
Fix Fresnel endpoint 500 error, restore coverage boundary visualization, minor polish.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐛 Issues to Fix
|
||||||
|
|
||||||
|
### 1. Fresnel Endpoint 500 Error
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```bash
|
||||||
|
curl "/api/terrain/fresnel?tx_lat=48.46&tx_lon=35.05&tx_height=30&rx_lat=48.47&rx_lon=35.06&rx_height=1.5&frequency=1800"
|
||||||
|
# Returns: 500 Internal Server Error
|
||||||
|
```
|
||||||
|
|
||||||
|
**Location:** `backend/app/api/routes/terrain.py`
|
||||||
|
|
||||||
|
**Likely cause:** Missing `rx_height` default or async issue in `los_service.check_fresnel_clearance()`
|
||||||
|
|
||||||
|
**Fix:**
|
||||||
|
```python
|
||||||
|
@router.get("/fresnel")
|
||||||
|
async def check_fresnel(
|
||||||
|
tx_lat: float,
|
||||||
|
tx_lon: float,
|
||||||
|
tx_height: float,
|
||||||
|
rx_lat: float,
|
||||||
|
rx_lon: float,
|
||||||
|
rx_height: float = 1.5, # Default receiver height
|
||||||
|
frequency: float = 1800 # Default frequency MHz
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
result = await los_service.check_fresnel_clearance(
|
||||||
|
tx_lat, tx_lon, tx_height,
|
||||||
|
rx_lat, rx_lon, rx_height,
|
||||||
|
frequency
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(500, f"Fresnel calculation error: {str(e)}")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Debug:** Check backend logs for actual error:
|
||||||
|
```bash
|
||||||
|
journalctl -u rfcp-backend -n 50 | grep -i error
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Coverage Boundary Not Showing
|
||||||
|
|
||||||
|
**Symptom:** Boundary contour line (-100 dBm) not visible on map after API integration
|
||||||
|
|
||||||
|
**Location:** `frontend/src/components/map/CoverageBoundary.tsx`
|
||||||
|
|
||||||
|
**Likely cause:** Component expecting old data format, not new API response
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
1. Is `CoverageBoundary` still mounted in map?
|
||||||
|
2. Does it receive `points` from coverage store?
|
||||||
|
3. Is boundary calculation using correct field (`rsrp` vs old field name)?
|
||||||
|
|
||||||
|
**Fix approach:**
|
||||||
|
```typescript
|
||||||
|
// CoverageBoundary.tsx
|
||||||
|
import { useCoverageStore } from '../../store/coverage';
|
||||||
|
|
||||||
|
export function CoverageBoundary() {
|
||||||
|
const { points, settings } = useCoverageStore();
|
||||||
|
|
||||||
|
// Generate boundary from API points
|
||||||
|
const boundaryPoints = useMemo(() => {
|
||||||
|
if (!points.length) return [];
|
||||||
|
|
||||||
|
// Filter points near threshold
|
||||||
|
const threshold = settings.min_signal; // -100 dBm
|
||||||
|
const tolerance = 5; // ±5 dBm
|
||||||
|
|
||||||
|
return points
|
||||||
|
.filter(p => Math.abs(p.rsrp - threshold) < tolerance)
|
||||||
|
.map(p => [p.lat, p.lon] as [number, number]);
|
||||||
|
}, [points, settings.min_signal]);
|
||||||
|
|
||||||
|
// ... rest of boundary rendering
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alternative:** Use convex hull or marching squares for proper contour:
|
||||||
|
```typescript
|
||||||
|
import { concaveman } from 'concaveman';
|
||||||
|
|
||||||
|
const boundaryPolygon = useMemo(() => {
|
||||||
|
const edgePoints = points
|
||||||
|
.filter(p => p.rsrp >= settings.min_signal && p.rsrp < settings.min_signal + 10)
|
||||||
|
.map(p => [p.lon, p.lat]);
|
||||||
|
|
||||||
|
if (edgePoints.length < 3) return null;
|
||||||
|
|
||||||
|
return concaveman(edgePoints, 2); // concavity factor
|
||||||
|
}, [points, settings.min_signal]);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Minor Polish
|
||||||
|
|
||||||
|
**a) Stats panel — show models used:**
|
||||||
|
```typescript
|
||||||
|
// StatsPanel.tsx
|
||||||
|
{lastCalculation && (
|
||||||
|
<div className="models-used">
|
||||||
|
<span className="label">Models:</span>
|
||||||
|
<div className="model-tags">
|
||||||
|
{lastCalculation.models.map(m => (
|
||||||
|
<span key={m} className="model-tag">{m}</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
|
**b) Loading state during long calculations:**
|
||||||
|
```typescript
|
||||||
|
// Show elapsed time during calculation
|
||||||
|
const [elapsed, setElapsed] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isCalculating) {
|
||||||
|
setElapsed(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = Date.now();
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setElapsed(Math.floor((Date.now() - start) / 1000));
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [isCalculating]);
|
||||||
|
|
||||||
|
// In render:
|
||||||
|
{isCalculating && (
|
||||||
|
<div className="calculating-status">
|
||||||
|
Calculating... {elapsed}s
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
```
|
||||||
|
|
||||||
|
**c) Error toast for API failures:**
|
||||||
|
```typescript
|
||||||
|
// In coverage store calculateCoverage()
|
||||||
|
catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : 'Calculation failed';
|
||||||
|
toast.error(message); // If using toast library
|
||||||
|
set({ error: message, isCalculating: false });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Tasks
|
||||||
|
|
||||||
|
- [ ] Fix Fresnel endpoint (backend)
|
||||||
|
- [ ] Debug and check logs for actual error
|
||||||
|
- [ ] Restore CoverageBoundary with API points
|
||||||
|
- [ ] Test boundary renders correctly
|
||||||
|
- [ ] Add elapsed time counter during calculation
|
||||||
|
- [ ] Add model tags to stats panel
|
||||||
|
- [ ] Test all presets still work
|
||||||
|
- [ ] Run integration test — should be 21/21
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Test Fresnel fix
|
||||||
|
curl "https://api.rfcp.eliah.one/api/terrain/fresnel?tx_lat=48.46&tx_lon=35.05&tx_height=30&rx_lat=48.47&rx_lon=35.06&rx_height=1.5&frequency=1800"
|
||||||
|
# Should return: {"clearance_percent": ..., "has_adequate_clearance": ...}
|
||||||
|
|
||||||
|
# 2. Run integration test
|
||||||
|
./rfcp-integration-test.sh
|
||||||
|
# Should be 21/21
|
||||||
|
|
||||||
|
# 3. Visual test
|
||||||
|
# - Calculate coverage
|
||||||
|
# - Verify boundary line appears at -100 dBm edge
|
||||||
|
# - Verify elapsed time shows during calculation
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📁 Files to Modify
|
||||||
|
|
||||||
|
```
|
||||||
|
backend/app/
|
||||||
|
├── api/routes/terrain.py # Fresnel fix
|
||||||
|
└── services/los_service.py # Check fresnel method
|
||||||
|
|
||||||
|
frontend/src/
|
||||||
|
├── components/
|
||||||
|
│ ├── map/CoverageBoundary.tsx # Fix boundary rendering
|
||||||
|
│ └── panels/
|
||||||
|
│ ├── CoverageStats.tsx # Add model tags
|
||||||
|
│ └── StatsPanel.tsx # Elapsed time
|
||||||
|
└── store/coverage.ts # Error handling
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
- Boundary can use simple edge detection or proper contour algorithm
|
||||||
|
- `concaveman` is lightweight (~2KB) for concave hull
|
||||||
|
- Elapsed time helps user know calculation is progressing
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Quick iteration — should be fast** 🚀
|
||||||
Reference in New Issue
Block a user