work
This commit is contained in:
parent
a729956898
commit
4b7ec8c058
|
@ -21,6 +21,7 @@ log = "0.4"
|
|||
wasm-logger = "0.2"
|
||||
serde-wasm-bindgen = "0.6"
|
||||
chrono = "0.4"
|
||||
itertools = "0.11"
|
||||
|
||||
[dependencies.js-sys]
|
||||
version = "0.3"
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
use web_sys::FileReader;
|
||||
use crate::loadar2;
|
||||
use crate::mode::Mode;
|
||||
use crate::rendering::render;
|
||||
use crate::scope::ScopeState;
|
||||
|
||||
pub fn should_newline(state: &mut ScopeState) -> bool {
|
||||
state.command_buf.starts_with("SET MODE")
|
||||
state.command_buf.starts_with("MODE SET")
|
||||
|| state.command_buf.starts_with("ELEVATION SET")
|
||||
}
|
||||
|
||||
pub fn exec(state: &mut ScopeState, command: String) {
|
||||
let tokens = command.split(' ').collect::<Vec<_>>();
|
||||
if command == "CLF OV" {
|
||||
state.file_input.click();
|
||||
} else if command == "CLF RELOAD" {
|
||||
|
@ -15,6 +18,67 @@ pub fn exec(state: &mut ScopeState, command: String) {
|
|||
state.command_buf_response_mode = true;
|
||||
render(state).expect("rerender failed");
|
||||
loadar2("file");
|
||||
} else if command.starts_with("MODE SET") {
|
||||
if tokens.len() < 3 {
|
||||
state.command_buf = "ARGUMENT INVALID".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
return
|
||||
} else {
|
||||
let mode = tokens[2];
|
||||
if let Some(ar2) = &state.ar2 {
|
||||
let types = ar2.elevations.get(&state.selected_elevation).unwrap();
|
||||
let valid_modes: Vec<_> = types[0].available_data.keys().collect();
|
||||
|
||||
if !valid_modes.contains(&&mode.to_string()) {
|
||||
state.command_buf = "ARGUMENT INVALID".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
return
|
||||
}
|
||||
|
||||
state.scope_mode = match mode {
|
||||
"REF" => Mode::Reflectivity,
|
||||
"VEL" => Mode::Velocity,
|
||||
"SW" => Mode::SpectrumWidth,
|
||||
"ZDR" => Mode::DifferentialReflectivity,
|
||||
"PHI" => Mode::DifferentialPhase,
|
||||
"RHO" => Mode::CorrelationCoefficient,
|
||||
"CFP" => Mode::ClutterFilterPowerRemoved,
|
||||
_ => unreachable!()
|
||||
};
|
||||
} else {
|
||||
state.command_buf = "CANNOT SET MODE\nRADAR INOPERATIVE".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if command.starts_with("ELEVATION SET") {
|
||||
if tokens.len() < 3 {
|
||||
state.command_buf = "ARGUMENT INVALID".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
return
|
||||
} else {
|
||||
let elev = tokens[2].to_string();
|
||||
if let Some(ar2) = &state.ar2 {
|
||||
let mut valid_elevs = vec![];
|
||||
for elev in ar2.elevations.keys() {
|
||||
valid_elevs.push(format!("{:0>3}", elev));
|
||||
}
|
||||
if !valid_elevs.contains(&elev) {
|
||||
state.command_buf = "ARGUMENT INVALID".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
return
|
||||
}
|
||||
let number: usize = elev.parse().unwrap();
|
||||
|
||||
// reset scope back to reflectivity which is included in every elevation
|
||||
state.scope_mode = Mode::Reflectivity;
|
||||
state.selected_elevation = number;
|
||||
} else {
|
||||
state.command_buf = "CANNOT SET MODE\nRADAR INOPERATIVE".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state.command_buf = "UNRECOGNIZED COMMAND".to_string();
|
||||
state.command_buf_response_mode = true;
|
||||
|
|
|
@ -15,6 +15,7 @@ use wasm_bindgen::prelude::*;
|
|||
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
||||
use crate::command::{exec, should_newline};
|
||||
use crate::mode::Mode;
|
||||
use crate::mode::Mode::Reflectivity;
|
||||
use crate::scope::{Preferences, RenderState, ScopeState};
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
@ -61,7 +62,8 @@ pub fn __nxrd_browser_init() -> AbiScopeState {
|
|||
},
|
||||
command_buf: String::new(),
|
||||
command_buf_response_mode: false,
|
||||
new_data_available: false
|
||||
new_data_available: false,
|
||||
selected_elevation: 1
|
||||
};
|
||||
|
||||
info!("nexrad-browser initialized successfully");
|
||||
|
@ -83,6 +85,8 @@ pub fn load_ar2(buf: &JsValue, scope: &mut AbiScopeState) {
|
|||
info!("new data chunk loaded");
|
||||
scope.0.ar2 = Some(loaded);
|
||||
scope.0.new_data_available = false;
|
||||
scope.0.scope_mode = Reflectivity;
|
||||
scope.0.command_buf = "NEW DATA LOADED SUCCESSFULLY".to_string();
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
@ -92,7 +96,8 @@ pub fn new_file_available(scope: &mut AbiScopeState) {
|
|||
|
||||
#[wasm_bindgen]
|
||||
pub fn keydown(state: &mut AbiScopeState, key: String) {
|
||||
if state.0.command_buf_response_mode {
|
||||
if state.0.command_buf_response_mode && (key == "Backspace" || key.len() == 1) {
|
||||
info!("resetting, key {} buf {}", key, state.0.command_buf);
|
||||
state.0.command_buf = String::new();
|
||||
state.0.command_buf_response_mode = false;
|
||||
}
|
||||
|
@ -101,8 +106,8 @@ pub fn keydown(state: &mut AbiScopeState, key: String) {
|
|||
state.0.command_buf = String::new();
|
||||
} else if key == "Enter" {
|
||||
let cmd = state.0.command_buf.clone();
|
||||
exec(&mut state.0, cmd.replace('\n', " "));
|
||||
state.0.command_buf = String::new();
|
||||
exec(&mut state.0, cmd.replace('\n', " "));
|
||||
} else if key == " " && should_newline(&mut state.0) {
|
||||
state.0.command_buf += "\n";
|
||||
} else if key == "Backspace" {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Mode {
|
||||
/// REF
|
||||
Reflectivity,
|
||||
|
@ -17,3 +17,42 @@ pub enum Mode {
|
|||
/// RADR INOP
|
||||
RadarInoperative
|
||||
}
|
||||
impl Mode {
|
||||
pub fn unselected(&self) -> &str {
|
||||
match self {
|
||||
Self::Reflectivity => " REF ",
|
||||
Self::Velocity => " VEL ",
|
||||
Self::SpectrumWidth => " SW ",
|
||||
Self::DifferentialReflectivity => " ZDR ",
|
||||
Self::DifferentialPhase => " PHI ",
|
||||
Self::CorrelationCoefficient => " RHO ",
|
||||
Self::ClutterFilterPowerRemoved => " CFP ",
|
||||
Self::RadarInoperative => " RADR INOP"
|
||||
}
|
||||
}
|
||||
pub fn selected(&self) -> &str {
|
||||
match self {
|
||||
Self::Reflectivity => ">REF<",
|
||||
Self::Velocity => ">VEL<",
|
||||
Self::SpectrumWidth => ">SW <",
|
||||
Self::DifferentialReflectivity => ">ZDR<",
|
||||
Self::DifferentialPhase => ">PHI<",
|
||||
Self::CorrelationCoefficient => ">RHO<",
|
||||
Self::ClutterFilterPowerRemoved => ">CFP<",
|
||||
Self::RadarInoperative => ">RADR INOP<"
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rname(&self) -> &str {
|
||||
match self {
|
||||
Self::Reflectivity => "REF",
|
||||
Self::Velocity => "VEL",
|
||||
Self::SpectrumWidth => "SW ",
|
||||
Self::DifferentialReflectivity => "ZDR",
|
||||
Self::DifferentialPhase => "PHI",
|
||||
Self::CorrelationCoefficient => "RHO",
|
||||
Self::ClutterFilterPowerRemoved => "CFP",
|
||||
Self::RadarInoperative => "NOP"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,9 @@
|
|||
use chrono::{DateTime, Timelike, Utc};
|
||||
use itertools::Itertools;
|
||||
use log::info;
|
||||
use wasm_bindgen::JsValue;
|
||||
use crate::mode::Mode;
|
||||
use crate::mode::Mode::{ClutterFilterPowerRemoved, CorrelationCoefficient, DifferentialPhase, DifferentialReflectivity, RadarInoperative, Reflectivity, SpectrumWidth, Velocity};
|
||||
use crate::rescaleCanvas;
|
||||
use crate::scope::ScopeState;
|
||||
use crate::utils::parse_date;
|
||||
|
@ -9,6 +13,8 @@ pub const TEXT_COLOR_RED: &str = "#ef0000";
|
|||
pub const TEXT_COLOR_GREEN: &str = "#4af626";
|
||||
pub const TEXT_COLOR_WHITE: &str = "#dedede";
|
||||
|
||||
pub const RANGE: usize = 50;
|
||||
|
||||
pub fn time(h: usize, m: usize, s: usize, tag_end: &str) -> String {
|
||||
format!("{:0>2}:{:0>2}:{:0>2}{}", h, m, s, tag_end)
|
||||
}
|
||||
|
@ -69,12 +75,92 @@ pub fn render(state: &mut ScopeState) -> Result<(), JsValue> {
|
|||
ctx.fill_text(&format!("{} VCP {} {}", ar2.volume_header_record.icao, ar2.meta_rda_status_data.vcp, vcp_string(ar2.meta_rda_status_data.vcp)), (canvas.width() - 50) as f64, 50.0 + (state.prefs.fcs as f64))?;
|
||||
let recorded = parse_date(ar2.volume_header_record.date, ar2.volume_header_record.time);
|
||||
let delay = time - recorded;
|
||||
ctx.fill_text(&format!("SITE DELAY {}:{}:{}", delay.num_hours(), delay.num_minutes() - (delay.num_hours() * 60), delay.num_seconds() - (delay.num_minutes() - (delay.num_hours() * 60) * 60)), (canvas.width() - 50) as f64, 50.0 + (state.prefs.fcs as f64 * 2.0))?;
|
||||
|
||||
let seconds = delay.num_seconds() % 60;
|
||||
let minutes = (delay.num_seconds() / 60) % 60;
|
||||
let hours = (delay.num_seconds() / 60) / 60;
|
||||
|
||||
ctx.fill_text(&format!("SITE DELAY {:0>2}:{:0>2}:{:0>2}", hours, minutes, seconds), (canvas.width() - 50) as f64, 50.0 + (state.prefs.fcs as f64 * 2.0))?;
|
||||
} else {
|
||||
ctx.fill_text("SITE INFORMATION UNAVAILABLE", (canvas.width() - 50) as f64, 50.0 + state.prefs.fcs as f64)?;
|
||||
ctx.fill_text("DELAY INFORMATION UNAVAILABLE", (canvas.width() - 50) as f64, 50.0 + (state.prefs.fcs * 2) as f64)?;
|
||||
}
|
||||
|
||||
// mode info
|
||||
ctx.fill_text("MODE", (canvas.width() - 50) as f64, (canvas.height() / 3) as f64)?;
|
||||
let modelines = [
|
||||
[Reflectivity, Velocity, SpectrumWidth].as_slice(),
|
||||
[DifferentialReflectivity, DifferentialPhase, CorrelationCoefficient].as_slice(),
|
||||
[ClutterFilterPowerRemoved, RadarInoperative].as_slice()
|
||||
];
|
||||
|
||||
let mut available_modes = vec![];
|
||||
|
||||
if let Some(ar2) = &state.ar2 {
|
||||
let types = ar2.elevations.get(&state.selected_elevation).unwrap();
|
||||
available_modes = types[0].available_data.keys().collect();
|
||||
}
|
||||
|
||||
for (line_no, line) in modelines.iter().enumerate() {
|
||||
let x = (canvas.width() - 50) as f64;
|
||||
let y = (canvas.height() / 3) as f64 + (state.prefs.fcs * (line_no + 1)) as f64;
|
||||
for (item_no, item) in line.iter().enumerate() {
|
||||
|
||||
let pad_start = item_no;
|
||||
let pad_end = 2 - item_no;
|
||||
let pad_start = " ".repeat(pad_start * 6);
|
||||
let pad_end = " ".repeat(pad_end * 6);
|
||||
let middle = if state.scope_mode == *item { item.selected() } else { item.unselected() };
|
||||
|
||||
if state.scope_mode == *item {
|
||||
// display selected color
|
||||
if *item == RadarInoperative {
|
||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_RED));
|
||||
ctx.fill_text(">RADR INOP<", x, y)?;
|
||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
||||
continue;
|
||||
} else {
|
||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_WHITE));
|
||||
}
|
||||
} else if *item == RadarInoperative {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if available_modes.contains(&&item.rname().to_string()) {
|
||||
ctx.fill_text(&format!(" {}{}{}", pad_start, middle, pad_end), x, y)?;
|
||||
}
|
||||
|
||||
if state.scope_mode == *item {
|
||||
// reset
|
||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.fill_text("ELEVATIONS", (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64)?;
|
||||
if let Some(ar2) = &state.ar2 {
|
||||
for (line_no, (elevation_no, scans)) in ar2.elevations.iter().sorted_by(|a, b| {
|
||||
Ord::cmp(&a.0, &b.0)
|
||||
}).enumerate() {
|
||||
if state.selected_elevation != *elevation_no {
|
||||
ctx.fill_text(&format!(" {:0>3} ", elevation_no), (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + (state.prefs.fcs * (line_no + 1)) as f64)?;
|
||||
} else {
|
||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_WHITE));
|
||||
ctx.fill_text(&format!(">{:0>3}<", elevation_no), (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + (state.prefs.fcs * (line_no + 1)) as f64)?;
|
||||
ctx.set_fill_style(&JsValue::from_str(TEXT_COLOR_GREEN));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ctx.fill_text("ELEVATION INFORMATION UNAVAILABLE", (canvas.width() - 50) as f64, ((canvas.height() / 7) * 4) as f64 + state.prefs.fcs as f64)?;
|
||||
}
|
||||
|
||||
// ACTUAL DATA RENDERING
|
||||
if let Some(ar2) = &state.ar2 {
|
||||
let px_per_km = canvas.height() / RANGE as u32;
|
||||
let xc = canvas.width() / 2;
|
||||
let yc = canvas.height() / 2;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -12,7 +12,8 @@ pub struct ScopeState {
|
|||
pub prefs: Preferences,
|
||||
pub command_buf: String,
|
||||
pub command_buf_response_mode: bool,
|
||||
pub new_data_available: bool
|
||||
pub new_data_available: bool,
|
||||
pub selected_elevation: usize
|
||||
}
|
||||
|
||||
pub struct RenderState {
|
||||
|
|
|
@ -23,7 +23,8 @@ pub mod message31;
|
|||
pub struct Nexrad2Chunk {
|
||||
pub volume_header_record: VolumeHeaderRecord,
|
||||
pub chunks: Vec<Vec<Message>>,
|
||||
pub meta_rda_status_data: Msg02RDAStatusData
|
||||
pub meta_rda_status_data: Msg02RDAStatusData,
|
||||
pub elevations: HashMap<usize, Vec<Message31>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -130,6 +131,7 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
trace!("Loaded - {:#?}", header);
|
||||
|
||||
let mut records: Vec<Vec<Message>> = vec![];
|
||||
let mut elevations: HashMap<usize, Vec<Message31>> = HashMap::new();
|
||||
|
||||
loop {
|
||||
// LDM records
|
||||
|
@ -344,17 +346,26 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
}
|
||||
}
|
||||
|
||||
let message = Message::Msg31(Message31 {
|
||||
let message31 = Message31 {
|
||||
header: header_struct,
|
||||
volume_info: volume_data,
|
||||
elevation_info: elevation_data,
|
||||
radial_info: radial_data,
|
||||
available_data: data_map
|
||||
});
|
||||
};
|
||||
|
||||
if let Some(elev_mut) = elevations.get_mut(&(message31.header.elevation_number as usize)) {
|
||||
elev_mut.push(message31.clone());
|
||||
} else {
|
||||
elevations.insert(message31.header.elevation_number as usize, vec![message31.clone()]);
|
||||
}
|
||||
|
||||
let message = Message::Msg31(message31);
|
||||
|
||||
trace!("{:#?}", message);
|
||||
|
||||
messages.push(message);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -384,8 +395,6 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
trace!("{} messages loaded from chunk", messages.len());
|
||||
|
||||
records.push(messages);
|
||||
|
||||
// break;
|
||||
}
|
||||
|
||||
info!("Extracting meta records");
|
||||
|
@ -414,7 +423,8 @@ pub fn parse_nx2_chunk(cursor: &mut (impl Read + Seek)) -> Result<Nexrad2Chunk,
|
|||
Ok(Nexrad2Chunk {
|
||||
volume_header_record: header,
|
||||
chunks: records,
|
||||
meta_rda_status_data: msg2
|
||||
meta_rda_status_data: msg2,
|
||||
elevations
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io::{Cursor, Read};
|
||||
|
||||
pub const MSG31_HEADER_LENGTH: usize = 4 + 4 + 2 + 2 + 4 + 1 + 1 + 2 + 1 + 1 + 1 + 1 + 4 + 1 + 1 + 2;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Message31Header {
|
||||
pub radar_identifier: String,
|
||||
|
@ -26,7 +27,7 @@ pub struct Message31Header {
|
|||
|
||||
pub const VOLUME_DATA_LENGTH: usize = 1 + 3 + 2 + 1 + 1 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 2 + 2;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct VolumeData {
|
||||
pub datablock_type: String,
|
||||
|
@ -49,7 +50,7 @@ pub struct VolumeData {
|
|||
|
||||
pub const ELEVATION_DATA_LENGTH: usize = 1 + 3 + 2 + 2 + 4;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct ElevationData {
|
||||
pub datablock_type: String,
|
||||
|
@ -61,7 +62,7 @@ pub struct ElevationData {
|
|||
|
||||
pub const RADIAL_DATA_LENGTH: usize = 1 + 3 + 2 + 2 + 4 + 4 + 2 + 2 + 4 + 4;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct RadialData {
|
||||
pub datablock_type: String,
|
||||
|
@ -78,7 +79,7 @@ pub struct RadialData {
|
|||
|
||||
pub const GENERIC_DATA_MOMENT_LEN: usize = 1 + 3 + 4 + 2 + 2 + 2 + 2 + 2 + 1 + 1 + 4 + 4;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct GenericDataMoment {
|
||||
pub datablock_type: String,
|
||||
|
@ -95,6 +96,7 @@ pub struct GenericDataMoment {
|
|||
pub offset: f32
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct DataMoment {
|
||||
pub gdm: GenericDataMoment,
|
||||
|
@ -107,7 +109,7 @@ impl Debug for DataMoment {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[cfg_attr(feature = "serde_derive", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Message31 {
|
||||
pub header: Message31Header,
|
||||
|
@ -116,3 +118,43 @@ pub struct Message31 {
|
|||
pub radial_info: Option<RadialData>,
|
||||
pub available_data: HashMap<String, DataMoment>
|
||||
}
|
||||
|
||||
impl DataMoment {
|
||||
pub fn scaled_data(&self) -> Vec<f32> {
|
||||
let mut gates = vec![0u16; self.gdm.data_moment_gate_count as usize];
|
||||
|
||||
if self.gdm.data_word_size == 8 {
|
||||
for byte in &self.data {
|
||||
gates.push(*byte as u16);
|
||||
}
|
||||
} else if self.gdm.data_word_size == 16 {
|
||||
for chunk in self.data.chunks(2) {
|
||||
gates.push(u16::from_be_bytes(chunk.try_into().unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
let mut scaled_data = vec![];
|
||||
|
||||
for gate in &gates {
|
||||
if *gate == 0 {
|
||||
// below threshold
|
||||
scaled_data.push(999.0);
|
||||
} else if *gate == 1 {
|
||||
// folded
|
||||
scaled_data.push(998.0);
|
||||
} else {
|
||||
scaled_data.push(scale_uint(*gate, self.gdm.offset, self.gdm.scale))
|
||||
}
|
||||
}
|
||||
|
||||
scaled_data
|
||||
}
|
||||
}
|
||||
|
||||
fn scale_uint(gate: u16, offset: f32, scale: f32) -> f32 {
|
||||
if scale == 0.0 {
|
||||
gate as f32
|
||||
} else {
|
||||
(gate as f32 - offset) / scale
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue