dspfrivs/src/waterfall.rs

109 lines
3.6 KiB
Rust

#[allow(unused_parens)]
use std::io::prelude::*;
use std::fs::File;
use std::env::args;
use std::f32::consts::PI;
fn bmp_header
(
image_width: usize, image_height: usize
) ->
Vec<u8>
{
let file_width = image_width*image_height + 1078;
let mut header:Vec<u8> = Vec::with_capacity(1078);
header.extend_from_slice(&"BM".as_bytes()); // bimp...
header.extend_from_slice(&(file_width as u32).to_le_bytes()); // filewidth
header.extend_from_slice(&0u32.to_le_bytes()); // forbidden field
header.extend_from_slice(&1078u32.to_le_bytes()); // data offset
header.extend_from_slice(&40u32.to_le_bytes()); // infoheader width
header.extend_from_slice(&(image_width as u32).to_le_bytes()); // pixel width
header.extend_from_slice(&(image_height as u32).to_le_bytes()); // pixel height
header.extend_from_slice(&1u16.to_le_bytes()); // number of planes
header.extend_from_slice(&8u16.to_le_bytes()); // bits per pixel
header.extend_from_slice(&0u32.to_le_bytes()); // compression type
header.extend_from_slice(&0u32.to_le_bytes()); // compressed image width
header.extend_from_slice(&1024u32.to_le_bytes()); // horizontal pixels/meter
header.extend_from_slice(&1024u32.to_le_bytes()); // vertical pixels/meter
header.extend_from_slice(&256u32.to_le_bytes()); // colors used
header.extend_from_slice(&0u32.to_le_bytes()); // "number of important colors"
assert_eq!(header.len(), 54);
for i in 0x00..=0xFF
{
header.push(i); // red
header.push(i); // green
header.push(i); // blue
header.push(0x00); // ?????
}
return header;
}
fn main()
{
let argv = args().collect::<Vec<String>>();
if argv.len() != 5
{
eprintln!("usage: waterfall <slice width> <gain> <output.bmp> <input.dat>");
return;
}
let width = argv[1].parse::<usize>().unwrap();
let gain = argv[2].parse::<f32>().unwrap();
let mut plot_file = File::create(&argv[3]).unwrap();
let mut signal_file = File::open(&argv[4]).unwrap();
let mut signal_data:Vec<u8> = Vec::new();
signal_file.read_to_end(&mut signal_data).unwrap();
let mut image_output:Vec<Vec<u8>> = Vec::new();
let mut global_peak:f32 = 0.0;
for data_slice in signal_data.chunks_exact(width*4)
{
let mut signal:Vec<f32> = Vec::with_capacity(width);
for chunk in data_slice.chunks_exact(4)
{
let mut sample_bytes:[u8;4] = [0x00; 4];
sample_bytes.copy_from_slice(chunk);
signal.push(f32::from_be_bytes(sample_bytes));
}
let mut image_line:Vec<u8> = Vec::with_capacity(width);
for n in 0..width
{
let mut new_i:f32 = 0.0;
let mut new_q:f32 = 0.0;
for t in 0..width
{
let (tq, ti) = (-2.0*(n as f32)*PI*(t as f32) / (width as f32)).sin_cos();
new_i += signal[t] * ti;
new_q += signal[t] * tq;
}
new_i /= (width as f32).sqrt();
new_q /= (width as f32).sqrt();
let new_power:f32 = gain*(new_i.powi(2) + new_q.powi(2)).sqrt();
global_peak = global_peak.max(new_power);
let new_pixel:u8 = (new_power*255.0).floor().min(255.0).max(0.0) as u8;
image_line.push(new_pixel);
}
image_output.push(image_line);
}
let height = image_output.len();
eprintln!("width: {}", width);
eprintln!("height: {}", height);
eprintln!("max value: {}", global_peak);
let mut image_data:Vec<u8> = Vec::with_capacity(height*width+1078);
image_data.extend_from_slice(&bmp_header(width, height));
for line in image_output.iter_mut().rev()
{
image_data.append(line);
}
plot_file.write_all(&image_data).unwrap();
}