pub const K_EFF_RB87: f64 = 4.0 * core::f64::consts::PI / 780.241e-9;
pub fn phase_sensitivity(k_eff: f64, t: f64) -> f64 {
k_eff * t * t
}
pub fn aharonov_bohm_rate(m: f64, source: f64, r: f64) -> f64 {
m * metrology::G * source / (metrology::HBAR * r)
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct AtomInterferometer {
pub t: f64,
pub contrast: f64,
pub atoms: f64,
pub cycle: f64,
pub diffraction: u32,
}
impl AtomInterferometer {
pub fn scale(&self) -> f64 {
self.diffraction as f64 * phase_sensitivity(K_EFF_RB87, self.t)
}
pub fn phase(&self, a: f64) -> f64 {
self.scale() * a
}
pub fn phase_noise(&self) -> f64 {
1.0 / (self.contrast * self.atoms.sqrt())
}
pub fn acceleration_noise(&self) -> f64 {
self.phase_noise() / self.scale()
}
pub fn acceleration_asd(&self) -> f64 {
self.acceleration_noise() * self.cycle.sqrt()
}
pub fn gradient_noise(&self, baseline: f64) -> f64 {
std::f64::consts::SQRT_2 * self.phase_noise() / (self.scale() * baseline)
}
pub fn gradient_asd(&self, baseline: f64) -> f64 {
self.gradient_noise(baseline) * self.cycle.sqrt()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn close(a: f64, b: f64, rel: f64) -> bool {
(a - b).abs() <= rel * b.abs()
}
#[test]
fn published_instruments() {
let carioqa = AtomInterferometer { t: 1.0, contrast: 0.8, atoms: 1e5, cycle: 3.5, diffraction: 2 };
assert!(close(carioqa.phase_noise(), 3.95e-3, 0.01));
assert!(close(carioqa.acceleration_asd(), 2.3e-10, 0.01));
assert!(close(AtomInterferometer { atoms: 1e6, ..carioqa }.acceleration_asd(), 7.3e-11, 0.01));
let grice = AtomInterferometer { t: 0.5, contrast: 0.43, atoms: 5e5, cycle: 2.0, diffraction: 2 };
assert!(close(grice.acceleration_asd(), 5.8e-10, 0.01));
let tri = AtomInterferometer { t: 5.0, contrast: 1.0, atoms: 1e6, cycle: 1.0, diffraction: 2 };
assert!(close(tri.gradient_noise(0.5), 3.5e-12, 0.01));
assert!(close(tri.phase(2.7e-6 * 0.5), 1087.0, 0.001));
}
#[test]
fn a_ground_gradiometer() {
let stray = AtomInterferometer { t: 0.085, contrast: 1.0, atoms: 1e5, cycle: 1.0 / 0.7, diffraction: 1 };
let eotvos = crate::local::EOTVOS;
assert!(close(stray.phase(150.0 * eotvos * 1.0), 17.5e-3, 0.01), "{}", stray.phase(150.0 * eotvos));
assert!(close(stray.gradient_asd(1.0) / eotvos, 45.9, 0.005), "{}", stray.gradient_asd(1.0) / eotvos);
assert!(close(stray.gradient_asd(1.0) / eotvos, 44.0, 0.05));
assert!(close(crate::local::averaging_time(466.0, 20.0), 543.0, 0.001));
let doubled = AtomInterferometer { diffraction: 2, ..stray };
assert!(close(doubled.gradient_asd(1.0) / stray.gradient_asd(1.0), 0.5, 1e-12));
assert!(close(stray.scale(), phase_sensitivity(K_EFF_RB87, 0.085), 1e-15));
}
#[test]
fn phase_and_potential() {
let s = phase_sensitivity(K_EFF_RB87, 0.160);
assert!((s / 4.123_07e5 - 1.0).abs() < 1e-5 && (s * metrology::G0 / 4.043e6 - 1.0).abs() < 1e-3);
let rb = 86.909 * metrology::AMU;
assert!((aharonov_bohm_rate(rb, 1.25, 0.07) / 1.631 - 1.0).abs() < 1e-3);
assert!((aharonov_bohm_rate(rb, 1.25, 0.14) / aharonov_bohm_rate(rb, 1.25, 0.07) - 0.5).abs() < 1e-12);
}
}