converted everything to float, which is faster apparently
This commit is contained in:
parent
91348f73cf
commit
4320e50a7a
|
@ -1,88 +1,16 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lapp"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "threnodyne"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lapp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||
"checksum lapp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60bf485afeba9437a275ad29a9383b03f2978450e7feceffb55be8c0dbad9829"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
|
|
|
@ -8,5 +8,3 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
lapp = "0.4.0"
|
||||
crossbeam-channel = "0.4.2"
|
||||
num_cpus = "1.12.0"
|
||||
|
|
21
src/chirp.rs
21
src/chirp.rs
|
@ -10,7 +10,7 @@ pub fn generate
|
|||
length: f32, // samples
|
||||
tail: f32, // proportion
|
||||
) ->
|
||||
Vec<i16>
|
||||
Vec<f32>
|
||||
{
|
||||
let freq_delta = (freq_hi - freq_lo) / (length * 2.0);
|
||||
|
||||
|
@ -18,7 +18,7 @@ pub fn generate
|
|||
let env_bot = length * tail;
|
||||
let env_top = length * (1.0 - tail);
|
||||
|
||||
let mut new_chirp:Vec<i16> = Vec::with_capacity(length.round() as usize);
|
||||
let mut new_chirp:Vec<f32> = Vec::with_capacity(length.round() as usize);
|
||||
for i in 0..(length.round() as usize)
|
||||
{
|
||||
let t = i as f32;
|
||||
|
@ -37,21 +37,16 @@ pub fn generate
|
|||
);
|
||||
|
||||
new_chirp.push(
|
||||
env *
|
||||
(
|
||||
32767.0 *
|
||||
env *
|
||||
PI * t *
|
||||
(
|
||||
PI * t *
|
||||
(
|
||||
freq_lo
|
||||
+
|
||||
(t * freq_delta)
|
||||
)
|
||||
freq_lo
|
||||
+
|
||||
(t * freq_delta)
|
||||
)
|
||||
.sin()
|
||||
)
|
||||
.round()
|
||||
as i16
|
||||
.sin()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@ use crate::gaussian;
|
|||
|
||||
struct SignalInput
|
||||
{
|
||||
template_rise: Vec<i64>,
|
||||
template_fall: Vec<i64>,
|
||||
norm_rise: i64,
|
||||
norm_fall: i64,
|
||||
symbol_size: i64,
|
||||
buffer: posi::Buffer<i64>,
|
||||
sum: i64,
|
||||
template_rise: Vec<f32>,
|
||||
template_fall: Vec<f32>,
|
||||
norm_rise: f32,
|
||||
norm_fall: f32,
|
||||
symbol_length: f32,
|
||||
buffer: posi::Buffer<f32>,
|
||||
sum: f32,
|
||||
}
|
||||
|
||||
impl SignalInput
|
||||
|
@ -29,35 +29,11 @@ impl SignalInput
|
|||
let lower_freq = (center_freq - deviation).max(0.0).min(1.0);
|
||||
|
||||
// these have to be reversed, since the input buffer shifts in at index 0 and is thus a mirror image
|
||||
let template_rise:Vec<i64> =
|
||||
(
|
||||
chirp::generate(upper_freq, lower_freq, symbol_length, 0.125)
|
||||
.into_iter()
|
||||
.map(|x| x as i64)
|
||||
.collect()
|
||||
);
|
||||
let template_fall:Vec<i64> =
|
||||
(
|
||||
chirp::generate(lower_freq, upper_freq, symbol_length, 0.125)
|
||||
.into_iter()
|
||||
.map(|x| x as i64)
|
||||
.collect()
|
||||
);
|
||||
|
||||
let norm_rise =
|
||||
(
|
||||
template_rise
|
||||
.iter()
|
||||
.map(|&x| x.abs())
|
||||
.sum()
|
||||
);
|
||||
let norm_fall =
|
||||
(
|
||||
template_rise
|
||||
.iter()
|
||||
.map(|&x| x.abs())
|
||||
.sum()
|
||||
);
|
||||
let template_rise:Vec<f32> = chirp::generate(upper_freq, lower_freq, symbol_length, 0.125);
|
||||
let template_fall:Vec<f32> = chirp::generate(lower_freq, upper_freq, symbol_length, 0.125);
|
||||
|
||||
let norm_rise = template_rise.iter().sum();
|
||||
let norm_fall = template_fall.iter().sum();
|
||||
|
||||
SignalInput
|
||||
{
|
||||
|
@ -65,18 +41,18 @@ impl SignalInput
|
|||
template_fall: template_fall,
|
||||
norm_rise: norm_rise,
|
||||
norm_fall: norm_fall,
|
||||
symbol_size: symbol_length.round() as i64,
|
||||
symbol_length: symbol_length,
|
||||
buffer: posi::Buffer::new(symbol_length.round() as usize),
|
||||
sum: 0,
|
||||
sum: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn ingest
|
||||
(
|
||||
&mut self,
|
||||
sample: i16,
|
||||
sample: f32,
|
||||
) {
|
||||
let new_value = sample as i64;
|
||||
let new_value = sample;
|
||||
let old_value = self.buffer.last();
|
||||
|
||||
self.sum -= old_value.abs();
|
||||
|
@ -89,14 +65,14 @@ impl SignalInput
|
|||
(
|
||||
&self,
|
||||
) ->
|
||||
(i64, i64)
|
||||
(f32, f32)
|
||||
{
|
||||
let local_signal = self.buffer.to_vec();
|
||||
|
||||
let mut rise_value = 0;
|
||||
let mut fall_value = 0;
|
||||
let mut rise_value:f32 = 0.0;
|
||||
let mut fall_value:f32 = 0.0;
|
||||
|
||||
if self.sum > 0
|
||||
if self.sum > 0.0
|
||||
{
|
||||
for (&a, &b) in
|
||||
(
|
||||
|
@ -116,19 +92,8 @@ impl SignalInput
|
|||
fall_value += a * b;
|
||||
}
|
||||
|
||||
rise_value =
|
||||
(
|
||||
(32768 * rise_value * self.symbol_size)
|
||||
/
|
||||
(self.norm_rise * self.sum)
|
||||
);
|
||||
|
||||
fall_value =
|
||||
(
|
||||
(32768 * fall_value * self.symbol_size)
|
||||
/
|
||||
(self.norm_fall * self.sum)
|
||||
);
|
||||
rise_value /= self.norm_rise * self.sum / self.symbol_length;
|
||||
fall_value /= self.norm_fall * self.sum / self.symbol_length;
|
||||
}
|
||||
|
||||
return (rise_value, fall_value);
|
||||
|
@ -137,9 +102,9 @@ impl SignalInput
|
|||
|
||||
struct CorrelFilter
|
||||
{
|
||||
kernel: Vec<i64>,
|
||||
buffer_rise: posi::Buffer<i64>,
|
||||
buffer_fall: posi::Buffer<i64>,
|
||||
kernel: Vec<f32>,
|
||||
buffer_rise: posi::Buffer<f32>,
|
||||
buffer_fall: posi::Buffer<f32>,
|
||||
}
|
||||
|
||||
impl CorrelFilter
|
||||
|
@ -164,24 +129,24 @@ impl CorrelFilter
|
|||
fn ingest
|
||||
(
|
||||
&mut self,
|
||||
rise: i64,
|
||||
fall: i64,
|
||||
rise: f32,
|
||||
fall: f32,
|
||||
) {
|
||||
self.buffer_rise.shift_in(rise);
|
||||
self.buffer_fall.shift_in(fall);
|
||||
}
|
||||
|
||||
fn hi_process
|
||||
fn lo_process
|
||||
(
|
||||
&self,
|
||||
) ->
|
||||
(i64, i64)
|
||||
(f32, f32)
|
||||
{
|
||||
let local_rise = self.buffer_rise.to_vec();
|
||||
let local_fall = self.buffer_fall.to_vec();
|
||||
|
||||
let mut rise_result:i64 = 0;
|
||||
let mut fall_result:i64 = 0;
|
||||
let mut rise_result:f32 = 0.0;
|
||||
let mut fall_result:f32 = 0.0;
|
||||
|
||||
for (&a, &b) in
|
||||
(
|
||||
|
@ -201,8 +166,16 @@ impl CorrelFilter
|
|||
fall_result += a * b;
|
||||
}
|
||||
|
||||
rise_result /= 32768;
|
||||
fall_result /= 32768;
|
||||
return (rise_result, fall_result);
|
||||
}
|
||||
|
||||
fn hi_process
|
||||
(
|
||||
&self,
|
||||
) ->
|
||||
(f32, f32)
|
||||
{
|
||||
let (rise_result, fall_result) = self.lo_process();
|
||||
|
||||
return
|
||||
(
|
||||
|
@ -210,62 +183,22 @@ impl CorrelFilter
|
|||
self.buffer_fall.mid() - fall_result,
|
||||
);
|
||||
}
|
||||
|
||||
fn lo_process
|
||||
(
|
||||
&self,
|
||||
) ->
|
||||
(i64, i64)
|
||||
{
|
||||
let local_rise = self.buffer_rise.to_vec();
|
||||
let local_fall = self.buffer_fall.to_vec();
|
||||
|
||||
let mut rise_result:i64 = 0;
|
||||
let mut fall_result:i64 = 0;
|
||||
|
||||
for (&a, &b) in
|
||||
(
|
||||
local_rise.iter()
|
||||
).zip(
|
||||
self.kernel.iter()
|
||||
) {
|
||||
rise_result += a * b;
|
||||
}
|
||||
|
||||
for (&a, &b) in
|
||||
(
|
||||
local_fall.iter()
|
||||
).zip(
|
||||
self.kernel.iter()
|
||||
) {
|
||||
fall_result += a * b;
|
||||
}
|
||||
|
||||
rise_result /= 32768;
|
||||
fall_result /= 32768;
|
||||
|
||||
return
|
||||
(
|
||||
rise_result,
|
||||
fall_result,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct CorrelOutput
|
||||
{
|
||||
rolling_max_decay: i64,
|
||||
squelch: i64,
|
||||
rolling_max_decay: f32,
|
||||
squelch: f32,
|
||||
|
||||
buffer_rise: posi::Buffer<i64>,
|
||||
rise_sum: i64,
|
||||
rise_maxima: Vec<i64>,
|
||||
rise_max_rolling: i64,
|
||||
buffer_rise: posi::Buffer<f32>,
|
||||
rise_sum: f32,
|
||||
rise_maxima: Vec<f32>,
|
||||
rise_max_rolling: f32,
|
||||
|
||||
buffer_fall: posi::Buffer<i64>,
|
||||
fall_sum: i64,
|
||||
fall_maxima: Vec<i64>,
|
||||
fall_max_rolling: i64,
|
||||
buffer_fall: posi::Buffer<f32>,
|
||||
fall_sum: f32,
|
||||
fall_maxima: Vec<f32>,
|
||||
fall_max_rolling: f32,
|
||||
}
|
||||
|
||||
impl CorrelOutput
|
||||
|
@ -278,26 +211,26 @@ impl CorrelOutput
|
|||
{
|
||||
CorrelOutput
|
||||
{
|
||||
rolling_max_decay: (size as i64) * 16,
|
||||
squelch: 0,
|
||||
rolling_max_decay: 1.0 - (0.1 / size as f32),
|
||||
squelch: 0.0,
|
||||
|
||||
buffer_rise: posi::Buffer::new(size),
|
||||
rise_sum: 0,
|
||||
rise_sum: 0.0,
|
||||
rise_maxima: Vec::new(),
|
||||
rise_max_rolling: 0,
|
||||
rise_max_rolling: 0.0,
|
||||
|
||||
buffer_fall: posi::Buffer::new(size),
|
||||
fall_sum: 0,
|
||||
fall_sum: 0.0,
|
||||
fall_maxima: Vec::new(),
|
||||
fall_max_rolling: 0,
|
||||
fall_max_rolling: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn ingest
|
||||
(
|
||||
&mut self,
|
||||
new_rise: i64,
|
||||
new_fall: i64,
|
||||
new_rise: f32,
|
||||
new_fall: f32,
|
||||
) {
|
||||
let old_rise = self.buffer_rise.last();
|
||||
let old_fall = self.buffer_fall.last();
|
||||
|
@ -308,12 +241,12 @@ impl CorrelOutput
|
|||
self.fall_sum += new_fall.abs();
|
||||
self.fall_sum -= old_fall.abs();
|
||||
|
||||
if let Ok(index) = self.rise_maxima.binary_search(&old_rise)
|
||||
if let Some(index) = self.rise_maxima.iter().position(|&x| x == old_rise)
|
||||
{
|
||||
self.rise_maxima.remove(index);
|
||||
}
|
||||
|
||||
if let Ok(index) = self.fall_maxima.binary_search(&old_fall)
|
||||
if let Some(index) = self.fall_maxima.iter().position(|&x| x == old_fall)
|
||||
{
|
||||
self.fall_maxima.remove(index);
|
||||
}
|
||||
|
@ -340,26 +273,11 @@ impl CorrelOutput
|
|||
let current_rise = self.buffer_rise.mid();
|
||||
let current_fall = self.buffer_fall.mid();
|
||||
|
||||
self.rise_max_rolling =
|
||||
(
|
||||
self.rise_max_rolling
|
||||
*
|
||||
(self.rolling_max_decay - 1)
|
||||
/
|
||||
self.rolling_max_decay
|
||||
);
|
||||
self.rise_max_rolling *= self.rolling_max_decay;
|
||||
self.fall_max_rolling *= self.rolling_max_decay;
|
||||
|
||||
self.fall_max_rolling =
|
||||
(
|
||||
self.fall_max_rolling
|
||||
*
|
||||
(self.rolling_max_decay - 1)
|
||||
/
|
||||
self.rolling_max_decay
|
||||
);
|
||||
|
||||
self.rise_max_rolling = self.rise_max_rolling.max(current_rise).max(current_fall / 2);
|
||||
self.fall_max_rolling = self.fall_max_rolling.max(current_fall).max(current_rise / 2);
|
||||
self.rise_max_rolling = self.rise_max_rolling.max(current_rise).max(current_fall / 2.0);
|
||||
self.fall_max_rolling = self.fall_max_rolling.max(current_fall).max(current_rise / 2.0);
|
||||
}
|
||||
|
||||
fn have_bit
|
||||
|
@ -371,8 +289,8 @@ impl CorrelOutput
|
|||
let current_rise = self.buffer_rise.mid();
|
||||
let current_fall = self.buffer_fall.mid();
|
||||
|
||||
let rise_max = *self.rise_maxima.last().unwrap_or(&0);
|
||||
let fall_max = *self.fall_maxima.last().unwrap_or(&0);
|
||||
let rise_max = *self.rise_maxima.last().unwrap_or(&0.0);
|
||||
let fall_max = *self.fall_maxima.last().unwrap_or(&0.0);
|
||||
|
||||
let mut have_rise:bool = false;
|
||||
let mut have_fall:bool = false;
|
||||
|
@ -382,9 +300,9 @@ impl CorrelOutput
|
|||
&&
|
||||
current_rise >= rise_max
|
||||
&&
|
||||
current_rise >= fall_max * 7 / 8
|
||||
current_rise >= fall_max * 7.0 / 8.0
|
||||
&&
|
||||
current_rise >= self.rise_max_rolling / 2
|
||||
current_rise >= self.rise_max_rolling / 2.0
|
||||
) {
|
||||
have_rise = true;
|
||||
}
|
||||
|
@ -394,9 +312,9 @@ impl CorrelOutput
|
|||
&&
|
||||
current_fall >= fall_max
|
||||
&&
|
||||
current_fall >= rise_max * 7 / 8
|
||||
current_fall >= rise_max * 7.0 / 8.0
|
||||
&&
|
||||
current_fall >= self.fall_max_rolling / 2
|
||||
current_fall >= self.fall_max_rolling / 2.0
|
||||
) {
|
||||
have_fall = true;
|
||||
}
|
||||
|
@ -495,8 +413,8 @@ impl Demodulator
|
|||
Demodulator
|
||||
{
|
||||
signal_input: SignalInput::new(center_freq, deviation, symbol_length),
|
||||
correl_lopass: CorrelFilter::new(deviation / 2.0),
|
||||
correl_hipass: CorrelFilter::new(deviation / 16.0),
|
||||
correl_lopass: CorrelFilter::new(deviation / 2.0), // these filter frequencies may need adjustment.
|
||||
correl_hipass: CorrelFilter::new(deviation / 4.0), // we don't really know how to set them Correctly, but they seem fairly easy to game.
|
||||
correl_output: CorrelOutput::new(symbol_length.round() as usize),
|
||||
accumulator: ByteAccumulator::new((symbol_length * 17.0 / 16.0).round() as usize),
|
||||
}
|
||||
|
@ -505,7 +423,7 @@ impl Demodulator
|
|||
pub fn process
|
||||
(
|
||||
&mut self,
|
||||
new_sample: i16,
|
||||
new_sample: f32,
|
||||
) ->
|
||||
Option<u8>
|
||||
{
|
||||
|
@ -529,22 +447,22 @@ impl Demodulator
|
|||
pub fn set_squelch
|
||||
(
|
||||
&mut self,
|
||||
value: u16,
|
||||
value: f32,
|
||||
) {
|
||||
self.correl_output.squelch = (value / 2) as i64;
|
||||
self.correl_output.squelch = value;
|
||||
}
|
||||
|
||||
pub fn dump_correl
|
||||
(
|
||||
&self,
|
||||
) ->
|
||||
(i64, i64)
|
||||
(f32, f32)
|
||||
{
|
||||
(
|
||||
self.correl_output.buffer_rise.mid(),
|
||||
self.correl_output.buffer_fall.mid(),
|
||||
//self.correl_output.rise_max_rolling,
|
||||
//self.correl_output.fall_max_rolling,
|
||||
//self.correl_output.buffer_rise.mid(),
|
||||
//self.correl_output.buffer_fall.mid(),
|
||||
self.correl_output.rise_max_rolling,
|
||||
self.correl_output.fall_max_rolling,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ pub struct Enmodulator
|
|||
{
|
||||
symbol_len: usize,
|
||||
guard_pad: usize,
|
||||
symbol_rise: Vec<i16>,
|
||||
symbol_fall: Vec<i16>,
|
||||
symbol_rise: Vec<f32>,
|
||||
symbol_fall: Vec<f32>,
|
||||
}
|
||||
|
||||
impl Enmodulator
|
||||
|
@ -23,8 +23,8 @@ impl Enmodulator
|
|||
let lower_freq = (center_freq - deviation).max(0.0).min(1.0);
|
||||
let upper_freq = (center_freq + deviation).max(0.0).min(1.0);
|
||||
|
||||
let symbol_rise:Vec<i16> = chirp::generate(lower_freq, upper_freq, symbol_len, 0.125);
|
||||
let symbol_fall:Vec<i16> = chirp::generate(upper_freq, lower_freq, symbol_len, 0.125);
|
||||
let symbol_rise:Vec<f32> = chirp::generate(lower_freq, upper_freq, symbol_len, 0.125);
|
||||
let symbol_fall:Vec<f32> = chirp::generate(upper_freq, lower_freq, symbol_len, 0.125);
|
||||
|
||||
Enmodulator
|
||||
{
|
||||
|
@ -40,9 +40,9 @@ impl Enmodulator
|
|||
&self,
|
||||
byte: u8,
|
||||
) ->
|
||||
Vec<i16>
|
||||
Vec<f32>
|
||||
{
|
||||
let mut new_signal:Vec<i16> =
|
||||
let mut new_signal:Vec<f32> =
|
||||
(
|
||||
Vec::with_capacity(
|
||||
(8 * self.symbol_len)
|
||||
|
@ -51,7 +51,7 @@ impl Enmodulator
|
|||
)
|
||||
);
|
||||
|
||||
new_signal.append(&mut vec![0; self.guard_pad]);
|
||||
new_signal.append(&mut vec![0.0; self.guard_pad]);
|
||||
|
||||
for i in 0..8
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ impl Enmodulator
|
|||
);
|
||||
}
|
||||
|
||||
new_signal.append(&mut vec![0; self.guard_pad]);
|
||||
new_signal.append(&mut vec![0.0; self.guard_pad]);
|
||||
|
||||
return new_signal;
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ pub fn generate
|
|||
(
|
||||
freq: f32,
|
||||
) ->
|
||||
Vec<i64>
|
||||
Vec<f32>
|
||||
{
|
||||
let width = 1.0 / (PI * freq);
|
||||
let radius = (width * 9.4).round().max(1.0) as isize;
|
||||
let radius = (width * 10.0).round().max(1.0) as isize;
|
||||
|
||||
let mut output:Vec<i64> = Vec::with_capacity(radius as usize * 2 + 1);
|
||||
let mut output:Vec<f32> = Vec::with_capacity(radius as usize * 2 + 1);
|
||||
|
||||
for t in
|
||||
(
|
||||
|
@ -23,18 +23,13 @@ pub fn generate
|
|||
) {
|
||||
output.push(
|
||||
(
|
||||
32768.0 *
|
||||
(
|
||||
-0.5 * (t / width).powi(2)
|
||||
)
|
||||
.exp()
|
||||
/
|
||||
(
|
||||
width * (2.0 * PI).sqrt()
|
||||
)
|
||||
-0.5 * (t / width).powi(2)
|
||||
)
|
||||
.exp()
|
||||
/
|
||||
(
|
||||
width * (2.0 * PI).sqrt()
|
||||
)
|
||||
.round()
|
||||
as i64
|
||||
);
|
||||
}
|
||||
|
||||
|
|
34
src/main.rs
34
src/main.rs
|
@ -28,7 +28,7 @@ fn main
|
|||
Chirps can provide substantial resistance to unfavorable channel conditions, which makes this program \
|
||||
potentially suitable for transmitting data over channels intended for narrowband voice communication.
|
||||
|
||||
Audio input/output is in raw 16-bit little-endian PCM format.
|
||||
Audio input/output is in 16-bit little-endian integer sample format.
|
||||
Data input/output is arbitrary binary data, which can be text, file contents, or whatever else.
|
||||
|
||||
Usage:
|
||||
|
@ -39,7 +39,7 @@ fn main
|
|||
-b, --bit-rate (default 50.0) - Data rate, in chirps (bits) per second. Be aware that lower values will increase system load.
|
||||
-f, --center-frequency (default 4000.0) - Center frequency of the signal in Hertz.
|
||||
-d, --deviation (default 2000.0) - Maximum range traversed above and below the center frequency by the signal.
|
||||
-t, --squelch (default 4000) - Minimum signal match degree for demodulation, from 0 (accept all) to 65535 (ignore all).
|
||||
-t, --squelch (default 0.4) - Minimum signal match degree for demodulation, from 0.0 (accept all) to 1.0 (ignore all).
|
||||
-a, --ascii-only - When demodulating, suppress all output that is not an ASCII character. Possibly useful if searching for text on a noisy channel.
|
||||
|
||||
-g, --debug (default 0) - If specified when demodulating, emits every nth correlation value in f32 form to threnodyne_rise.dat and threnodyne_fall.dat.
|
||||
|
@ -56,7 +56,7 @@ fn main
|
|||
let arg_bitrate= args.get_float("bit-rate");
|
||||
let arg_centerfreq = args.get_float("center-frequency");
|
||||
let arg_deviation = args.get_float("deviation");
|
||||
let arg_squelch = args.get_integer("squelch");
|
||||
let arg_squelch = args.get_float("squelch");
|
||||
let arg_ascii = args.get_bool("ascii-only");
|
||||
let arg_debug = args.get_integer("debug");
|
||||
|
||||
|
@ -103,9 +103,9 @@ fn main
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if arg_squelch < 0 || arg_squelch > 65535
|
||||
if arg_squelch < 0.0
|
||||
{
|
||||
eprintln!("threnodyne: the squelch threshold must be at least zero and no more than 65535 ({} won't do)", arg_squelch);
|
||||
eprintln!("threnodyne: the squelch threshold must be at least 0.0 ({} won't do)", arg_squelch);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ fn main
|
|||
{
|
||||
let enmodulator = enmodulation::Enmodulator::new(center_freq, deviation, symbol_len);
|
||||
|
||||
let mut output_buffer:Vec<u8> = Vec::with_capacity(symbol_size);
|
||||
let mut output_buffer:Vec<u8> = Vec::with_capacity(symbol_size * 2);
|
||||
|
||||
let wall_start = Instant::now();
|
||||
let mut process_time = Duration::new(0,0);
|
||||
|
@ -147,7 +147,12 @@ fn main
|
|||
|
||||
for &sample in signal.iter()
|
||||
{
|
||||
output_buffer.extend_from_slice(&sample.to_le_bytes());
|
||||
output_buffer.extend_from_slice(
|
||||
&(
|
||||
(sample * 32767.0) as i16
|
||||
)
|
||||
.to_le_bytes()
|
||||
);
|
||||
}
|
||||
|
||||
process_time += iter_time.elapsed();
|
||||
|
@ -176,7 +181,7 @@ fn main
|
|||
{
|
||||
let mut demodulator = demodulation::Demodulator::new(center_freq, deviation, symbol_len);
|
||||
|
||||
demodulator.set_squelch(arg_squelch as u16);
|
||||
demodulator.set_squelch(arg_squelch);
|
||||
|
||||
let wall_start = Instant::now();
|
||||
let mut process_time = Duration::new(0,0);
|
||||
|
@ -244,7 +249,12 @@ fn main
|
|||
|
||||
let iter_time = Instant::now();
|
||||
|
||||
let sample = i16::from_le_bytes(sample_bytes);
|
||||
let sample =
|
||||
(
|
||||
i16::from_le_bytes(sample_bytes) as f32
|
||||
/
|
||||
32767.0
|
||||
);
|
||||
let demod_result = demodulator.process(sample);
|
||||
|
||||
if let Some((risefile, fallfile)) = &mut debug_files
|
||||
|
@ -252,10 +262,8 @@ fn main
|
|||
if samples_processed % (arg_debug as usize) == 0
|
||||
{
|
||||
let (riseval, fallval) = demodulator.dump_correl();
|
||||
let riseval_f = (riseval as f32) / 32768.0;
|
||||
let fallval_f = (fallval as f32) / 32768.0;
|
||||
risefile.write_all(&riseval_f.to_be_bytes()).expect("write failed on rise debug file");
|
||||
fallfile.write_all(&fallval_f.to_be_bytes()).expect("write failed on fall debug file");
|
||||
risefile.write_all(&riseval.to_be_bytes()).expect("write failed on rise debug file");
|
||||
fallfile.write_all(&fallval.to_be_bytes()).expect("write failed on fall debug file");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue