1include!(concat!(env!("OUT_DIR"), "/cossin_table.rs"));
2
3pub fn cossin(mut phase: i32) -> (i32, i32) {
15 let mut octant = phase as u32;
16 if octant & (1 << 29) != 0 {
17 phase = !phase;
19 }
20
21 const ALIGN_MSB: usize = 32 - 16 - 1;
23
24 phase = (((phase as u32) << 3) >> (32 - COSSIN_DEPTH - ALIGN_MSB)) as _;
26
27 let lookup = COSSIN[(phase >> ALIGN_MSB) as usize];
28 phase &= (1 << ALIGN_MSB) - 1;
29
30 phase -= 1 << (ALIGN_MSB - 1);
33
34 const PI4: i32 = (core::f64::consts::FRAC_PI_4 * (1 << 16) as f64) as _;
40 let dphi = (phase * PI4) >> 16;
42
43 let mut cos = (lookup & 0xffff) as i32 + (1 << 16);
46 let mut sin = (lookup >> 16) as i32;
47
48 let dcos = (sin * dphi) >> COSSIN_DEPTH;
49 let dsin = (cos * dphi) >> (COSSIN_DEPTH + 1);
50
51 cos = (cos << (ALIGN_MSB - 1)) - dcos;
52 sin = (sin << ALIGN_MSB) + dsin;
53
54 octant ^= octant >> 1;
56 if octant & (1 << 29) != 0 {
57 (cos, sin) = (sin, cos);
58 }
59 if octant & (1 << 30) != 0 {
60 cos = -cos;
61 }
62 if octant & (1 << 31) != 0 {
63 sin = -sin;
64 }
65
66 (cos, sin)
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use core::f64::consts::PI;
73
74 #[test]
75 fn cossin_error_max_rms_all_phase() {
76 const AMPLITUDE: f64 = (1i64 << 31) as f64 - 0.85 * (1i64 << 15) as f64;
78 const MAX_PHASE: f64 = (1i64 << 32) as _;
79 let mut rms_err = (0f64, 0f64);
80 let mut sum_err = (0f64, 0f64);
81 let mut max_err = (0f64, 0f64);
82 let mut sum = (0f64, 0f64);
83 let mut demod = (0f64, 0f64);
84
85 const PHASE_DEPTH: usize = 20;
90
91 for phase in 0..(1 << PHASE_DEPTH) {
92 let phase = (phase << (32 - PHASE_DEPTH)) as i32;
93 let have = cossin(phase);
94 let have = (have.0 as f64 / AMPLITUDE, have.1 as f64 / AMPLITUDE);
98
99 let radian_phase = 2. * PI * phase as f64 / MAX_PHASE;
100 let want = (radian_phase.cos(), radian_phase.sin());
101
102 sum.0 += have.0;
103 sum.1 += have.1;
104
105 demod.0 += have.0 * want.0 - have.1 * want.1;
106 demod.1 += have.1 * want.0 + have.0 * want.1;
107
108 let err = (have.0 - want.0, have.1 - want.1);
109
110 sum_err.0 += err.0;
111 sum_err.1 += err.1;
112
113 rms_err.0 += err.0 * err.0;
114 rms_err.1 += err.1 * err.1;
115
116 max_err.0 = max_err.0.max(err.0.abs());
117 max_err.1 = max_err.1.max(err.1.abs());
118 }
119 rms_err.0 /= (1 << PHASE_DEPTH) as f64;
120 rms_err.1 /= (1 << PHASE_DEPTH) as f64;
121
122 println!("sum: {:.2e} {:.2e}", sum.0, sum.1);
123 println!("demod: {:.2e} {:.2e}", demod.0, demod.1);
124 println!("sum_err: {:.2e} {:.2e}", sum_err.0, sum_err.1);
125 println!("rms: {:.2e} {:.2e}", rms_err.0.sqrt(), rms_err.1.sqrt());
126 println!("max: {:.2e} {:.2e}", max_err.0, max_err.1);
127
128 assert!(sum.0.abs() < 4e-10);
129 assert!(sum.1.abs() < 3e-8);
130
131 assert!(demod.0.abs() < 4e-10);
132 assert!(demod.1.abs() < 1e-8);
133
134 assert!(sum_err.0.abs() < 4e-10);
135 assert!(sum_err.1.abs() < 4e-10);
136
137 assert!(rms_err.0.sqrt() < 4e-6);
138 assert!(rms_err.1.sqrt() < 4e-6);
139
140 assert!(max_err.0 < 1e-5);
141 assert!(max_err.1 < 1e-5);
142 }
143}