xous-core/libs/cos_table/src/lib.rs
bunnie 597e24cd99 add a table-based implementation of cosine
this is a space-optimized implementation of cosine. it's about
12k smaller than core lib's "proper" cosine.

Gives about 9 bits amplitude resolution, and divides the waveform
into 1024 time positions. Good enough for generating tones on
a crappy speaker.

Later on if anyone needs to "really" do cosine or sine, we'll have
a footgun for them, but...let's hope Rust fixes issue
https://github.com/rust-lang/rust/issues/105734 before then, and
we can deprecate this library in favor of the mathematically
accurate and canonical cosine implementation.
2023-01-02 17:47:48 +08:00

77 lines
No EOL
3.3 KiB
Rust

/*
COS_TABLE generated with:
#! /usr/bin/env python3
import math
print("const COS_TABLE: [u8; 256] = [", end="")
for i in range(256):
if i % 16 == 0:
print("\n", end="")
print("{:03}, ".format(int(255.0 * math.cos( ((3.14159265359 / 2.0) / 256) * float(i) ))), end="")
print("];")
*/
/// One quarter of a cosine wave. The other four quarters are generated through symmetry.
const COS_TABLE: [u8; 256] = [
255, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 253,
253, 253, 253, 253, 253, 252, 252, 252, 252, 252, 251, 251, 251, 250, 250, 250,
250, 249, 249, 249, 248, 248, 248, 247, 247, 246, 246, 246, 245, 245, 244, 244,
244, 243, 243, 242, 242, 241, 241, 240, 240, 239, 239, 238, 237, 237, 236, 236,
235, 234, 234, 233, 233, 232, 231, 231, 230, 229, 229, 228, 227, 227, 226, 225,
224, 224, 223, 222, 221, 221, 220, 219, 218, 217, 217, 216, 215, 214, 213, 212,
212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 201, 200, 199, 198,
197, 196, 195, 194, 193, 192, 191, 189, 188, 187, 186, 185, 184, 183, 182, 181,
180, 179, 178, 176, 175, 174, 173, 172, 171, 170, 168, 167, 166, 165, 164, 162,
161, 160, 159, 158, 156, 155, 154, 153, 151, 150, 149, 148, 146, 145, 144, 142,
141, 140, 139, 137, 136, 135, 133, 132, 131, 129, 128, 127, 125, 124, 122, 121,
120, 118, 117, 116, 114, 113, 111, 110, 109, 107, 106, 104, 103, 101, 100, 099,
097, 096, 094, 093, 091, 090, 088, 087, 085, 084, 082, 081, 079, 078, 077, 075,
074, 072, 071, 069, 068, 066, 064, 063, 061, 060, 058, 057, 055, 054, 052, 051,
049, 048, 046, 045, 043, 042, 040, 038, 037, 035, 034, 032, 031, 029, 028, 026,
024, 023, 021, 020, 018, 017, 015, 014, 012, 010, 009, 007, 006, 004, 003, 001,
];
use std::f32::consts::PI;
enum Quadrant {
FirstNormNorm,
SecondReverseInvert,
ThirdNormInvert,
FourthReverseNorm,
}
/// LUT-based cosine computation. Has an `8-bit` resolution. Used to coarsely compute
/// a cosine without relying on `std` functions. The concerns driving this implementation are:
///
/// - code size
/// - xous-core issue #285 and https://github.com/rust-lang/rust/issues/105734
///
/// The issue above means any attempt to use `cos` (or any transcendental function) from
/// Rust math library leads to a link time error. Until Rust can fix this regression we have
/// to implement our own cosine function, or use `thin` LTO which adds about 7% to the size
/// of the kernel, making it by far the single largest contributing factor to kernel bloat.
pub fn cos(a: f32) -> f32 {
let pos = a % (2.0 * PI);
let q = if pos < (PI / 2.0) {
Quadrant::FirstNormNorm
} else if pos < (PI) {
Quadrant::SecondReverseInvert
} else if pos < (3.0 * PI / 2.0) {
Quadrant::ThirdNormInvert
} else {
Quadrant::FourthReverseNorm
};
let idx = (256.0 * (a % (PI / 2.0)) / (PI / 2.0)) as usize;
match q {
Quadrant::FirstNormNorm => {
(COS_TABLE[idx] as f32) / 255.0
},
Quadrant::SecondReverseInvert => {
(COS_TABLE[255-idx] as f32) / -255.0
},
Quadrant::ThirdNormInvert => {
(COS_TABLE[idx] as f32) / -255.0
},
Quadrant::FourthReverseNorm => {
(COS_TABLE[255-idx] as f32) / 255.0
}
}
}