use crate::error::{Error, Result};
use crate::utility::bits::count_ones;
use crate::sequence::msequence::MSequence;
#[derive(Debug, Clone)]
pub struct BSequence {
s: Vec<u32>,
num_bits: usize,
num_bits_msb: usize,
bit_mask_msb: u32,
}
impl BSequence {
pub fn new(num_bits: usize) -> Self {
let s_len = (num_bits + 31) / 32;
let num_bits_msb = if num_bits % 32 == 0 { 32 } else { num_bits % 32 };
let bit_mask_msb = 1u32.checked_shl(num_bits_msb as u32).unwrap_or(0).wrapping_sub(1);
let mut bs = Self {
s: vec![0; s_len],
num_bits,
num_bits_msb,
bit_mask_msb,
};
bs.reset();
bs
}
pub fn create_ccodes(qa: &mut BSequence, qb: &mut BSequence) -> Result<()> {
if qa.num_bits != qb.num_bits {
return Err(Error::Config("sequence lengths must match".into()));
}
if qa.num_bits < 8 {
return Err(Error::Config("sequence too short".into()));
}
if qa.num_bits % 8 != 0 {
return Err(Error::Config("sequence must be multiple of 8".into()));
}
let num_bytes = qa.num_bits / 8;
let mut a = vec![0u8; num_bytes];
let mut b = vec![0u8; num_bytes];
a[num_bytes - 1] = 0xb8; b[num_bytes - 1] = 0xb7;
let mut n = 1;
while n < num_bytes {
let i_n1 = num_bytes - n;
let i_n0 = num_bytes - 2 * n;
let (a_start, a_end) = a.split_at_mut(i_n1);
let (b_start, b_end) = b.split_at_mut(i_n1);
a_start[i_n0..i_n1].copy_from_slice(&a_end[0..n]);
b_start[i_n0..i_n1].copy_from_slice(&a_end[0..n]);
a_end[0..n].copy_from_slice(&b_end[0..n]);
for i in 0..n {
b[num_bytes - i - 1] ^= 0xff;
}
n *= 2;
}
qa.init(&a);
qb.init(&b);
Ok(())
}
pub fn from_msequence(ms: &mut MSequence) -> Result<Self> {
let mut bs = BSequence::new(ms.get_length() as usize);
bs.reset();
for _ in 0..ms.get_length() {
bs.push(ms.advance());
}
Ok(bs)
}
pub fn reset(&mut self) {
self.s.fill(0);
}
pub fn init(&mut self, v: &[u8]) {
let mut k = 0;
let mut byte = 0;
let mut mask = 0x80;
for i in 0..self.num_bits {
if (i % 8) == 0 {
byte = v[k];
k += 1;
mask = 0x80;
}
self.push(if (byte & mask) != 0 { 1 } else { 0 });
mask >>= 1;
}
}
pub fn print(&self) {
println!("<bsequence, bits={}>", self.num_bits);
}
pub fn push(&mut self, bit: u32) {
let p = 32;
self.s[0] = (self.s[0] << 1) & self.bit_mask_msb;
for i in 1..self.s.len() {
let overflow = (self.s[i] >> (p - 1)) & 1;
self.s[i] <<= 1;
self.s[i - 1] |= overflow;
}
let l = self.s.len();
self.s[l - 1] |= bit & 1;
}
pub fn circshift(&mut self) {
let msb_mask = 1u32.checked_shl(self.num_bits_msb as u32 - 1).unwrap_or(0);
let b = (self.s[0] & msb_mask) >> (self.num_bits_msb - 1);
self.push(b);
}
pub fn correlate(&self, bs2: &BSequence) -> Result<i32> {
if self.s.len() != bs2.s.len() {
return Err(Error::Config("binary sequences must be the same length".into()));
}
let mut rxy = 0;
for (a, b) in self.s.iter().zip(bs2.s.iter()) {
let chunk = !(*a ^ *b);
rxy += count_ones(chunk) as i32;
}
rxy -= 32 - self.num_bits_msb as i32;
Ok(rxy)
}
pub fn add(&self, bs2: &BSequence, bs3: &mut BSequence) -> Result<()> {
if self.s.len() != bs2.s.len() || self.s.len() != bs3.s.len() {
return Err(Error::Config("binary sequences must be same length".into()));
}
for ((a, b), c) in self.s.iter().zip(bs2.s.iter()).zip(bs3.s.iter_mut()) {
*c = *a ^ *b;
}
Ok(())
}
pub fn mul(&self, bs2: &BSequence, bs3: &mut BSequence) -> Result<()> {
if self.s.len() != bs2.s.len() || self.s.len() != bs3.s.len() {
return Err(Error::Config("binary sequences must be same length".into()));
}
for ((a, b), c) in self.s.iter().zip(bs2.s.iter()).zip(bs3.s.iter_mut()) {
*c = *a & *b;
}
Ok(())
}
pub fn accumulate(&self) -> u32 {
self.s.iter().map(|&x| count_ones(x)).sum()
}
pub fn get_length(&self) -> usize {
self.num_bits
}
pub fn index(&self, i: usize) -> Result<u32> {
if i >= self.num_bits {
return Err(Error::Config(format!("invalid index {}", i)));
}
let k = self.s.len() - 1 - i / 32;
Ok((self.s[k] >> (i % 32)) & 1)
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_macro::autotest_annotate;
use crate::sequence::msequence::MSequence;
#[test]
#[autotest_annotate(autotest_bsequence_init)]
fn test_bsequence_init() {
let v = [0xf0u8, 0xcau8];
let mut q = BSequence::new(16);
q.init(&v);
assert_eq!(q.index(15).unwrap(), 1);
assert_eq!(q.index(14).unwrap(), 1);
assert_eq!(q.index(13).unwrap(), 1);
assert_eq!(q.index(12).unwrap(), 1);
assert_eq!(q.index(11).unwrap(), 0);
assert_eq!(q.index(10).unwrap(), 0);
assert_eq!(q.index(9).unwrap(), 0);
assert_eq!(q.index(8).unwrap(), 0);
assert_eq!(q.index(7).unwrap(), 1);
assert_eq!(q.index(6).unwrap(), 1);
assert_eq!(q.index(5).unwrap(), 0);
assert_eq!(q.index(4).unwrap(), 0);
assert_eq!(q.index(3).unwrap(), 1);
assert_eq!(q.index(2).unwrap(), 0);
assert_eq!(q.index(1).unwrap(), 1);
assert_eq!(q.index(0).unwrap(), 0);
}
#[test]
#[autotest_annotate(autotest_bsequence_init_msequence)]
fn test_bsequence_init_msequence() {
let mut ms = MSequence::create_default(4).unwrap();
let bs = BSequence::from_msequence(&mut ms).unwrap();
assert_eq!(bs.get_length(), ms.get_length() as usize);
}
#[test]
#[autotest_annotate(autotest_bsequence_correlate)]
fn test_bsequence_correlate() {
let v0 = [0xf0u8, 0xcau8];
let v1 = [0xcbu8, 0x1eu8];
let mut q0 = BSequence::new(16);
let mut q1 = BSequence::new(16);
q0.init(&v0);
q1.init(&v1);
assert_eq!(q0.correlate(&q1).unwrap(), 7);
}
#[test]
#[autotest_annotate(autotest_bsequence_add)]
fn test_bsequence_add() {
let v0 = [0xf0u8, 0xcau8];
let v1 = [0xcbu8, 0x1eu8];
let mut q0 = BSequence::new(16);
let mut q1 = BSequence::new(16);
q0.init(&v0);
q1.init(&v1);
let mut r = BSequence::new(16);
q0.add(&q1, &mut r).unwrap();
assert_eq!(r.index(15).unwrap(), 0);
assert_eq!(r.index(14).unwrap(), 0);
assert_eq!(r.index(13).unwrap(), 1);
assert_eq!(r.index(12).unwrap(), 1);
assert_eq!(r.index(11).unwrap(), 1);
assert_eq!(r.index(10).unwrap(), 0);
assert_eq!(r.index(9).unwrap(), 1);
assert_eq!(r.index(8).unwrap(), 1);
assert_eq!(r.index(7).unwrap(), 1);
assert_eq!(r.index(6).unwrap(), 1);
assert_eq!(r.index(5).unwrap(), 0);
assert_eq!(r.index(4).unwrap(), 1);
assert_eq!(r.index(3).unwrap(), 0);
assert_eq!(r.index(2).unwrap(), 1);
assert_eq!(r.index(1).unwrap(), 0);
assert_eq!(r.index(0).unwrap(), 0);
}
#[test]
#[autotest_annotate(autotest_bsequence_mul)]
fn test_bsequence_mul() {
let v0 = [0xf0u8, 0xcau8];
let v1 = [0xcbu8, 0x1eu8];
let mut q0 = BSequence::new(16);
let mut q1 = BSequence::new(16);
q0.init(&v0);
q1.init(&v1);
let mut r = BSequence::new(16);
q0.mul(&q1, &mut r).unwrap();
assert_eq!(r.index(15).unwrap(), 1);
assert_eq!(r.index(14).unwrap(), 1);
assert_eq!(r.index(13).unwrap(), 0);
assert_eq!(r.index(12).unwrap(), 0);
assert_eq!(r.index(11).unwrap(), 0);
assert_eq!(r.index(10).unwrap(), 0);
assert_eq!(r.index(9).unwrap(), 0);
assert_eq!(r.index(8).unwrap(), 0);
assert_eq!(r.index(7).unwrap(), 0);
assert_eq!(r.index(6).unwrap(), 0);
assert_eq!(r.index(5).unwrap(), 0);
assert_eq!(r.index(4).unwrap(), 0);
assert_eq!(r.index(3).unwrap(), 1);
assert_eq!(r.index(2).unwrap(), 0);
assert_eq!(r.index(1).unwrap(), 1);
assert_eq!(r.index(0).unwrap(), 0);
}
#[test]
#[autotest_annotate(autotest_bsequence_accumulate)]
fn test_bsequence_accumulate() {
let v = [0xf0u8, 0xcau8];
let mut q = BSequence::new(16);
q.init(&v);
assert_eq!(q.accumulate(), 8);
}
fn complementary_codes_test(n: usize) {
let mut a = BSequence::new(n);
let mut b = BSequence::new(n);
BSequence::create_ccodes(&mut a, &mut b).unwrap();
let mut ax = BSequence::new(n);
let mut bx = BSequence::new(n);
BSequence::create_ccodes(&mut ax, &mut bx).unwrap();
for i in 0..n {
let raa = 2 * a.correlate(&ax).unwrap() - n as i32;
let rbb = 2 * b.correlate(&bx).unwrap() - n as i32;
if i == 0 {
assert_eq!(raa + rbb, 2 * n as i32);
} else {
assert_eq!(raa + rbb, 0);
}
ax.circshift();
bx.circshift();
}
}
#[test]
#[autotest_annotate(autotest_complementary_code_n8)]
fn test_complementary_code_n8() { complementary_codes_test(8); }
#[test]
#[autotest_annotate(autotest_complementary_code_n16)]
fn test_complementary_code_n16() { complementary_codes_test(16); }
#[test]
#[autotest_annotate(autotest_complementary_code_n32)]
fn test_complementary_code_n32() { complementary_codes_test(32); }
#[test]
#[autotest_annotate(autotest_complementary_code_n64)]
fn test_complementary_code_n64() { complementary_codes_test(64); }
#[test]
#[autotest_annotate(autotest_complementary_code_n128)]
fn test_complementary_code_n128() { complementary_codes_test(128); }
#[test]
#[autotest_annotate(autotest_complementary_code_n256)]
fn test_complementary_code_n256() { complementary_codes_test(256); }
#[test]
#[autotest_annotate(autotest_complementary_code_n512)]
fn test_complementary_code_n512() { complementary_codes_test(512); }
}