use std::f64::consts::PI;
use supernovas::{Accuracy, CatalogEntry, Frame, Observer, Site, Time, Weather, uvw};
const REF_LAT: f64 = 39.802;
const REF_LON: f64 = -114.842;
const REF_HEIGHT: f64 = 1909.0;
const SAMPLE_RATE_HZ: f64 = 2.4e9;
const SAMPLE_NS: f64 = 1e9 / SAMPLE_RATE_HZ;
const SUBBAND_BW_HZ: f64 = 1e6;
#[allow(clippy::similar_names, clippy::items_after_statements)]
fn main() -> Result<(), Box<dyn core::error::Error>> {
const EARTH_R: f64 = 6_378_137.0;
let ref_site =
Site::from_degrees(REF_LAT, REF_LON, REF_HEIGHT)?.with_weather(Weather::standard());
let offsets_m: [(f64, f64); 9] = [
(100.0, 0.0),
(200.0, 0.0),
(300.0, 0.0),
(0.0, 100.0),
(0.0, 200.0),
(100.0, 100.0),
(-100.0, 0.0),
(-200.0, 0.0),
(0.0, -100.0),
];
let lat_rad = REF_LAT.to_radians();
let m_to_deg_lon = (180.0 / PI) / (EARTH_R * lat_rad.cos());
let m_to_deg_lat = (180.0 / PI) / EARTH_R;
let mut sites = Vec::with_capacity(10);
sites.push(ref_site);
for (e, n) in offsets_m {
sites.push(Site::from_degrees(
REF_LAT + n * m_to_deg_lat,
REF_LON + e * m_to_deg_lon,
REF_HEIGHT,
)?);
}
let observer = Observer::Geodetic(sites[0]);
let time = Time::from_utc_jd(2_461_236.75, 37, 0.0)?;
let frame = Frame::new(Accuracy::Reduced, &observer, &time)?;
let cyg_a = CatalogEntry::icrs("Cyg A", "19:59:28.36".parse()?, "+40:44:02.1".parse()?)?;
let source_dir = frame.source_gcrs_direction(&cyg_a)?;
let (ref_pos, ref_vel) = frame.site_gcrs_posvel(&sites[0])?;
println!("F-engine delay tracking — 10-antenna array");
println!(" reference : antenna 0 at ({REF_LAT}°, {REF_LON}°, {REF_HEIGHT} m)");
println!(" source : Cygnus A");
println!(" epoch : JD 2461236.750 UTC");
println!(" ADC clock : {SAMPLE_RATE_HZ:.1e} Hz ({SAMPLE_NS:.3} ns/sample)");
println!(" subband : {SUBBAND_BW_HZ:.0} Hz");
println!();
println!("ant τ [ns] rate [ns/s] samples frac φ_sub [°]");
println!("--- ------------- ------------- ------- ------ ----------");
for (i, site) in sites.iter().enumerate() {
let (pos, vel) = frame.site_gcrs_posvel(site)?;
let rel_pos = pos - ref_pos;
let rel_vel = vel - ref_vel;
let u = uvw::uvw(&rel_pos, Some(&rel_vel), source_dir)?;
let tau_ns = u.delay_ns();
let rate_ns_per_s = u.delay_rate_ns_per_s(source_dir, &rel_vel);
let n_samples = tau_ns / SAMPLE_NS;
let n_int = n_samples.floor();
let frac = n_samples - n_int;
let phase_deg = 360.0 * SUBBAND_BW_HZ * (frac * SAMPLE_NS) * 1e-9;
println!(
" {i:>2} {tau_ns:>13.3} {rate_ns_per_s:>13.4} {n_int:>7.0} {frac:>6.3} {phase_deg:>10.3}"
);
}
println!();
println!("FPGA load per antenna:");
println!(" coarse delay (FIFO) : integer `samples` column");
println!(
" fine delay (rotator) : `φ_sub` applied per subband at {SUBBAND_BW_HZ:.0} Hz spacing"
);
println!(" update rate : `rate` ns/s drives the once-per-integration delay walk");
Ok(())
}