from sqlalchemy.orm import Session from app.core.diffraction import deygout from app.core.fresnel import los_analysis from app.core.geo import GeoPoint, sample_path from app.core.propagation import manual_link_budget from app.models.link import LinkBudgetRequest, LinkBudgetResponse from app.services.terrain import surface_profile_from_points from app.services.vegetation import vegetation_loss_along def link_budget(request: LinkBudgetRequest, db: Session | None = None) -> LinkBudgetResponse: if request.model != "manual": raise NotImplementedError(f"{request.model} link model is implemented in a later stage") tx = GeoPoint(lat=request.tx.lat, lon=request.tx.lon) rx = GeoPoint(lat=request.rx.lat, lon=request.rx.lon) points = sample_path(tx, rx, 256) freq_hz = request.frequency_mhz * 1_000_000 surface_profile = surface_profile_from_points( points, include_buildings=request.include_buildings, include_canopy=False, db=db, ) los_result = los_analysis( surface_profile, tx_height_agl=request.tx.height_agl, rx_height_agl=request.rx.height_agl, freq_hz=freq_hz, k=request.k_factor, ) diffraction_db = deygout( surface_profile, tx_height_agl=request.tx.height_agl, rx_height_agl=request.rx.height_agl, freq_hz=freq_hz, ) vegetation_db = vegetation_loss_along( points, freq_hz=freq_hz, include_vegetation=request.include_vegetation, ) budget = manual_link_budget( tx=tx, rx=rx, tx_power_dbm=request.tx.power_dbm, tx_gain_dbi=request.tx.gain_dbi, rx_gain_dbi=request.rx.gain_dbi, sensitivity_dbm=request.rx.sensitivity_dbm, frequency_mhz=request.frequency_mhz, diffraction_db=diffraction_db, vegetation_db=vegetation_db, fresnel_clear=los_result.los_clear, ) return LinkBudgetResponse(**budget.__dict__)