mirror of https://github.com/ArduPilot/ardupilot
Tools: Web: FilterReview: add notch tracking overlay
This commit is contained in:
parent
6443eab963
commit
15601e4139
|
@ -1,5 +1,293 @@
|
||||||
// A js tool for plotting ArduPilot batch log data
|
// A js tool for plotting ArduPilot batch log data
|
||||||
|
|
||||||
|
// Generic Class to hold source for notch target
|
||||||
|
class NotchTarget {
|
||||||
|
constructor(log, msg_name, key_name, name, mode_value) {
|
||||||
|
this.name = name
|
||||||
|
this.mode_value = mode_value
|
||||||
|
this.data = []
|
||||||
|
|
||||||
|
// Don't always need log data (static notch)
|
||||||
|
if (log == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab data from log
|
||||||
|
log.parseAtOffset(msg_name)
|
||||||
|
if ((log.messages[msg_name] == null) || (log.messages[msg_name].length == 0)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert ket into array if needed
|
||||||
|
if (!Array.isArray(key_name)) {
|
||||||
|
key_name = [key_name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab all given keys to data struct
|
||||||
|
this.data.time = []
|
||||||
|
for (var j=0; j<key_name.length; j++) {
|
||||||
|
this.data[key_name[j]] = []
|
||||||
|
}
|
||||||
|
for (var i=0; i < log.messages[msg_name].time_boot_ms.length; i++) {
|
||||||
|
this.data.time[i] = log.messages[msg_name].time_boot_ms[i] / 1000
|
||||||
|
for (var j=0; j<key_name.length; j++) {
|
||||||
|
this.data[key_name[j]][i] = log.messages[msg_name][key_name[j]][i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_target_freq(config) {
|
||||||
|
if ((Object.keys(this.data).length == 0) || (this.data.time == null)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const start_index = find_start_index(this.data.time)
|
||||||
|
const end_index = find_end_index(this.data.time)
|
||||||
|
if (config.ref == 0) {
|
||||||
|
return { freq:[config.freq, config.freq], time:[this.data.time[start_index], this.data.time[end_index]] }
|
||||||
|
}
|
||||||
|
|
||||||
|
var freq = []
|
||||||
|
for (let j=start_index;j<end_index;j++) {
|
||||||
|
freq.push(this.get_target_freq_index(config, j))
|
||||||
|
}
|
||||||
|
return { freq:freq, time:this.data.time.slice(start_index, end_index) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracking mode specific classes
|
||||||
|
class StaticTarget extends NotchTarget {
|
||||||
|
constructor(log) {
|
||||||
|
super(null, null, null, "Static", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
get_target_freq(config) {
|
||||||
|
const start_time = parseFloat(document.getElementById("TimeStart").value)
|
||||||
|
const end_time = parseFloat(document.getElementById("TimeEnd").value)
|
||||||
|
return { freq:[config.freq, config.freq], time:[start_time, end_time] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThrottleTarget extends NotchTarget {
|
||||||
|
constructor(log) {
|
||||||
|
super(log, "RATE", "AOut", "Throttle", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
get_target_freq_index(config, index) {
|
||||||
|
const motors_throttle = math.max(0, this.data.AOut[index])
|
||||||
|
return config.freq * math.max(config.min_ratio, math.sqrt(motors_throttle / config.ref))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RPMTarget extends NotchTarget {
|
||||||
|
constructor(log, instance, mode_value) {
|
||||||
|
const key = "rpm" + instance
|
||||||
|
super(log, "RPM", key, "RPM" + instance, mode_value)
|
||||||
|
this.key = key
|
||||||
|
}
|
||||||
|
|
||||||
|
get_target_freq_index(config, index) {
|
||||||
|
const rpm = this.data[this.key][index]
|
||||||
|
if (rpm > 0) {
|
||||||
|
return math.max(config.freq, rpm * config.ref * (1.0/60.0))
|
||||||
|
}
|
||||||
|
return config.freq
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ESCTarget extends NotchTarget {
|
||||||
|
constructor(log) {
|
||||||
|
super(null, null, null, "ESC", 3)
|
||||||
|
|
||||||
|
// Grab data from log, have to do it a little differently to get instances
|
||||||
|
const msg = "ESC"
|
||||||
|
log.parseAtOffset(msg)
|
||||||
|
if ((log.messages[msg] == null) || (log.messages[msg].length == 0)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual RPM
|
||||||
|
var instances = 0
|
||||||
|
for (let i=0;i<16;i++) {
|
||||||
|
const inst_msg = msg + "[" + i + "]"
|
||||||
|
if (log.messages[inst_msg] != null) {
|
||||||
|
this.data[i] = { time:[], freq:[] }
|
||||||
|
for (var j=0; j < log.messages[inst_msg].time_boot_ms.length; j++) {
|
||||||
|
this.data[i].time[j] = log.messages[inst_msg].time_boot_ms[j] / 1000
|
||||||
|
this.data[i].freq[j] = log.messages[inst_msg].RPM[j] / 60
|
||||||
|
}
|
||||||
|
instances++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Average RPM
|
||||||
|
this.data.avg_freq = []
|
||||||
|
this.data.avg_time = []
|
||||||
|
var inst = []
|
||||||
|
for (let i=0;i<instances;i++) {
|
||||||
|
inst[i] = { rpm:null, time_ms:null }
|
||||||
|
}
|
||||||
|
for (let i=0;i<log.messages[msg].length;i++) {
|
||||||
|
// Update instance
|
||||||
|
const instance = log.messages[msg][i].Instance
|
||||||
|
const time_ms = log.messages[msg][i].time_boot_ms
|
||||||
|
inst[instance].rpm = log.messages[msg][i].RPM
|
||||||
|
inst[instance].time_ms = time_ms
|
||||||
|
|
||||||
|
// Invalidate any instance that has timed out
|
||||||
|
for (let j=0;j<instances;j++) {
|
||||||
|
if ((j != instance) && (inst[j].time_ms != null) && ((time_ms - inst[j].time_ms) > 1000)) {
|
||||||
|
inst[j].time_ms = null
|
||||||
|
inst[j].rpm = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a full set of valid instances take average
|
||||||
|
var expected_count = 0
|
||||||
|
var count = 0
|
||||||
|
var sum = 0
|
||||||
|
for (let j=0;j<instances;j++) {
|
||||||
|
if (inst[j].rpm != null) {
|
||||||
|
count++
|
||||||
|
sum += inst[j].rpm
|
||||||
|
}
|
||||||
|
if (inst[j].time_ms != null) {
|
||||||
|
expected_count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((count > 0) && (count == expected_count)) {
|
||||||
|
this.data.avg_freq.push((sum / count) / 60)
|
||||||
|
this.data.avg_time.push(time_ms / 1000)
|
||||||
|
|
||||||
|
// Invalidate used values
|
||||||
|
for (let j=0;j<instances;j++) {
|
||||||
|
inst[j].rpm = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_target_freq(config) {
|
||||||
|
if (this.data.length == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const dynamic = (config.options & (1<<1)) != 0
|
||||||
|
if (dynamic) {
|
||||||
|
// Tracking individual motor RPM's
|
||||||
|
let freq = []
|
||||||
|
let time = []
|
||||||
|
|
||||||
|
for (let i = 0; i < this.data.length; i++) {
|
||||||
|
const start_index = find_start_index(this.data[i].time)
|
||||||
|
const end_index = find_end_index(this.data[i].time)
|
||||||
|
|
||||||
|
let inst_freq = this.data[i].freq.slice(start_index, end_index)
|
||||||
|
for (let j = 0; j < inst_freq.length; j++) {
|
||||||
|
inst_freq[j] = math.max(inst_freq[j], config.freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.push(...this.data[i].time.slice(start_index, end_index))
|
||||||
|
freq.push(...inst_freq)
|
||||||
|
|
||||||
|
// Add NAN to remove line from end back to the start
|
||||||
|
time.push(NaN)
|
||||||
|
freq.push(NaN)
|
||||||
|
}
|
||||||
|
return { freq:freq, time:time }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracking average motor rpm
|
||||||
|
const start_index = find_start_index(this.data.avg_time)
|
||||||
|
const end_index = find_end_index(this.data.avg_time)
|
||||||
|
|
||||||
|
let freq = this.data.avg_freq.slice(start_index, end_index)
|
||||||
|
for (let j = 0; j < freq.length; j++) {
|
||||||
|
freq[j] = math.max(freq[j], config.freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { freq:freq, time:this.data.avg_time.slice(start_index, end_index) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FFTTarget extends NotchTarget {
|
||||||
|
constructor(log) {
|
||||||
|
super(log, "FTN1", "PkAvg", "FFT", 4)
|
||||||
|
|
||||||
|
// Grab data from log, have to do it a little differently to get instances
|
||||||
|
const msg = "FTN2"
|
||||||
|
log.parseAtOffset(msg)
|
||||||
|
if ((log.messages[msg] == null) || (log.messages[msg].length == 0)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i=0;i<3;i++) {
|
||||||
|
// FFT can track three peaks
|
||||||
|
const inst_msg = msg + "[" + i + "]"
|
||||||
|
if (log.messages[inst_msg] != null) {
|
||||||
|
this.data[i] = { time:[], freq:[] }
|
||||||
|
for (var j=0; j < log.messages[inst_msg].time_boot_ms.length; j++) {
|
||||||
|
|
||||||
|
// Do noise weighting between axis to get a single frequency
|
||||||
|
// Same as `get_weighted_freq_hz` function in AP_GyroFFT
|
||||||
|
const energy_x = log.messages[inst_msg].EnX[j]
|
||||||
|
const energy_y = log.messages[inst_msg].EnY[j]
|
||||||
|
const freq_x = log.messages[inst_msg].PkX[j]
|
||||||
|
const freq_y = log.messages[inst_msg].PkY[j]
|
||||||
|
|
||||||
|
if ((energy_x > 0) && (energy_y > 0)) {
|
||||||
|
// Weighted by relative energy
|
||||||
|
this.data[i].freq[j] = (freq_x*energy_x + freq_y*energy_y) / (energy_x + energy_y)
|
||||||
|
} else {
|
||||||
|
// Just take average
|
||||||
|
this.data[i].freq[j] = (freq_x + freq_y) * 0.5
|
||||||
|
}
|
||||||
|
this.data[i].time[j] = log.messages[inst_msg].time_boot_ms[j] / 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_target_freq(config) {
|
||||||
|
const dynamic = (config.options & (1<<1)) != 0
|
||||||
|
if (dynamic) {
|
||||||
|
// Tracking multiple peaks
|
||||||
|
let freq = []
|
||||||
|
let time = []
|
||||||
|
|
||||||
|
for (let i = 0; i < this.data.length; i++) {
|
||||||
|
const start_index = find_start_index(this.data[i].time)
|
||||||
|
const end_index = find_end_index(this.data[i].time)
|
||||||
|
|
||||||
|
let inst_freq = this.data[i].freq.slice(start_index, end_index)
|
||||||
|
for (let j = 0; j < inst_freq.length; j++) {
|
||||||
|
inst_freq[j] = math.max(inst_freq[j], config.freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.push(...this.data[i].time.slice(start_index, end_index))
|
||||||
|
freq.push(...inst_freq)
|
||||||
|
|
||||||
|
// Add NAN to remove line from end back to the start
|
||||||
|
time.push(NaN)
|
||||||
|
freq.push(NaN)
|
||||||
|
}
|
||||||
|
return { freq:freq, time:time }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just center peak
|
||||||
|
const start_index = find_start_index(this.data.time)
|
||||||
|
const end_index = find_end_index(this.data.time)
|
||||||
|
|
||||||
|
let freq = this.data.PkAvg.slice(start_index, end_index)
|
||||||
|
for (let j = 0; j < freq.length; j++) {
|
||||||
|
freq[j] = math.max(freq[j], config.freq)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { freq:freq, time:this.data.time.slice(start_index, end_index) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// return hanning window array of given length (in tensorflow format)
|
// return hanning window array of given length (in tensorflow format)
|
||||||
function hanning(len) {
|
function hanning(len) {
|
||||||
const half = tf.scalar(0.5)
|
const half = tf.scalar(0.5)
|
||||||
|
@ -141,6 +429,7 @@ function run_batch_fft(data_set) {
|
||||||
// Setup plots with no data
|
// Setup plots with no data
|
||||||
var Spectrogram = {}
|
var Spectrogram = {}
|
||||||
var fft_plot = {}
|
var fft_plot = {}
|
||||||
|
const max_num_harmonics = 8
|
||||||
function reset() {
|
function reset() {
|
||||||
let axis = ["X" , "Y", "Z"]
|
let axis = ["X" , "Y", "Z"]
|
||||||
|
|
||||||
|
@ -160,9 +449,6 @@ function reset() {
|
||||||
|
|
||||||
// Clear extra text
|
// Clear extra text
|
||||||
document.getElementById("FFTWindowInfo").innerHTML = ""
|
document.getElementById("FFTWindowInfo").innerHTML = ""
|
||||||
document.getElementById("Gyro0_info").innerHTML = "<br>"
|
|
||||||
document.getElementById("Gyro1_info").innerHTML = "<br>"
|
|
||||||
document.getElementById("Gyro2_info").innerHTML = "<br>"
|
|
||||||
document.getElementById("Gyro0_FFT_info").innerHTML = "<br><br><br>"
|
document.getElementById("Gyro0_FFT_info").innerHTML = "<br><br><br>"
|
||||||
document.getElementById("Gyro1_FFT_info").innerHTML = "<br><br><br>"
|
document.getElementById("Gyro1_FFT_info").innerHTML = "<br><br><br>"
|
||||||
document.getElementById("Gyro2_FFT_info").innerHTML = "<br><br><br>"
|
document.getElementById("Gyro2_FFT_info").innerHTML = "<br><br><br>"
|
||||||
|
@ -191,29 +477,52 @@ function reset() {
|
||||||
fft_plot.layout = {
|
fft_plot.layout = {
|
||||||
xaxis: {title: {text: ""}, type: "linear"},
|
xaxis: {title: {text: ""}, type: "linear"},
|
||||||
yaxis: {title: {text: ""}},
|
yaxis: {title: {text: ""}},
|
||||||
|
showlegend: true,
|
||||||
|
legend: {itemclick: false, itemdoubleclick: false },
|
||||||
|
margin: { b: 50, l: 50, r: 50, t: 20 }
|
||||||
}
|
}
|
||||||
|
|
||||||
var FFTPlot = document.getElementById("FFTPlot")
|
var FFTPlot = document.getElementById("FFTPlot")
|
||||||
Plotly.purge(FFTPlot)
|
Plotly.purge(FFTPlot)
|
||||||
Plotly.newPlot(FFTPlot, fft_plot.data, fft_plot.layout, {displaylogo: false});
|
Plotly.newPlot(FFTPlot, fft_plot.data, fft_plot.layout, {displaylogo: false});
|
||||||
|
|
||||||
// Disable legend click (could probably hook this into the set the ticky boxes)
|
|
||||||
FFTPlot.on('plotly_legendclick', function(data) { return false })
|
|
||||||
|
|
||||||
// Spectrogram setup
|
// Spectrogram setup
|
||||||
// Add surface
|
// Add surface
|
||||||
Spectrogram.data = [{
|
Spectrogram.data = [{
|
||||||
type:"heatmap",
|
type:"heatmap",
|
||||||
colorbar: {title: {side: "right", text: ""}},
|
colorbar: {title: {side: "right", text: ""}, orientation: "h"},
|
||||||
transpose: true,
|
transpose: true,
|
||||||
zsmooth: "best",
|
zsmooth: "best",
|
||||||
hovertemplate: ""
|
hovertemplate: ""
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
// Add tracking lines
|
||||||
|
// Two harmonic notch filters each with upto 8 harmonics
|
||||||
|
for (let i=0;i<2;i++) {
|
||||||
|
let Group_name = "Notch " + (i+1)
|
||||||
|
let dash = (i == 0) ? "solid" : "dot"
|
||||||
|
for (let j=0;j<max_num_harmonics;j++) {
|
||||||
|
let name = (j == 0) ? "Fundamental" : "Harmonic " + j
|
||||||
|
Spectrogram.data.push({
|
||||||
|
type:"scatter",
|
||||||
|
mode: "lines",
|
||||||
|
line: { width: 4, dash: dash },
|
||||||
|
visible: false,
|
||||||
|
name: name,
|
||||||
|
meta: Group_name + "<br>" + name,
|
||||||
|
legendgroup: i,
|
||||||
|
legendgrouptitle: { text: "" }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Define Layout
|
// Define Layout
|
||||||
Spectrogram.layout = {
|
Spectrogram.layout = {
|
||||||
xaxis: {title: {text: "Time (s)"}},
|
xaxis: {title: {text: "Time (s)"}},
|
||||||
yaxis: {title: {text: ""}, type: "linear"},
|
yaxis: {title: {text: ""}, type: "linear"},
|
||||||
|
showlegend: true,
|
||||||
|
legend: {itemclick: false, itemdoubleclick: false },
|
||||||
|
margin: { b: 50, l: 50, r: 50, t: 20 }
|
||||||
}
|
}
|
||||||
|
|
||||||
var SpectrogramPlot = document.getElementById("Spectrogram")
|
var SpectrogramPlot = document.getElementById("Spectrogram")
|
||||||
|
@ -473,6 +782,57 @@ function redraw_Spectrogram() {
|
||||||
Spectrogram.data[0].z[j] = amplitude_scale.fun(math.dotMultiply(Gyro_batch[batch_instance].FFT[axis][index], window_correction))
|
Spectrogram.data[0].z[j] = amplitude_scale.fun(math.dotMultiply(Gyro_batch[batch_instance].FFT[axis][index], window_correction))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup tracking lines
|
||||||
|
const tracking_hovertemplate = "<extra></extra>%{meta}<br>" + "%{x:.2f} s<br>" + frequency_scale.hover("y")
|
||||||
|
for (let i=0;i<HNotch_setup.length;i++) {
|
||||||
|
// Plus one for the spectrogram plot
|
||||||
|
const plot_offset = i * max_num_harmonics + 1
|
||||||
|
|
||||||
|
// Hide all
|
||||||
|
for (let j=0;j<max_num_harmonics;j++) {
|
||||||
|
Spectrogram.data[plot_offset + j].visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notch disabled, nothing to do
|
||||||
|
if ((HNotch_setup[i].enable <= 0) || (HNotch_setup[i].harmonics <= 0)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find configured tracking source
|
||||||
|
let tracking
|
||||||
|
for (let j=0;j<tracking_methods.length;j++) {
|
||||||
|
if (HNotch_setup[i].mode == tracking_methods[j].mode_value) {
|
||||||
|
tracking = tracking_methods[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid mode
|
||||||
|
if (tracking == null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const Group_name = "Notch " + (i+1) + ": " + tracking.name
|
||||||
|
const fundamental = tracking.get_target_freq(HNotch_setup[i])
|
||||||
|
|
||||||
|
// Enable each harmonic
|
||||||
|
for (let j=0;j<max_num_harmonics;j++) {
|
||||||
|
if ((HNotch_setup[i].harmonics & (1<<j)) == 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const harmonic_freq = math.dotMultiply(fundamental.freq, j+1)
|
||||||
|
if (harmonic_freq == null) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
Spectrogram.data[plot_offset + j].visible = true
|
||||||
|
Spectrogram.data[plot_offset + j].x = fundamental.time
|
||||||
|
Spectrogram.data[plot_offset + j].y = frequency_scale.fun(harmonic_freq)
|
||||||
|
Spectrogram.data[plot_offset + j].hovertemplate = tracking_hovertemplate
|
||||||
|
Spectrogram.data[plot_offset + j].legendgrouptitle.text = Group_name
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Plotly.redraw("Spectrogram")
|
Plotly.redraw("Spectrogram")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,12 +880,50 @@ function get_param_value(param_log, name) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_HNotch_param_names() {
|
||||||
|
prefix = ["INS_HNTCH_", "INS_HNTC2_"]
|
||||||
|
ret = []
|
||||||
|
for (let i = 0; i < prefix.length; i++) {
|
||||||
|
ret[i] = {enable: prefix[i] + "ENABLE",
|
||||||
|
mode: prefix[i] + "MODE",
|
||||||
|
freq: prefix[i] + "FREQ",
|
||||||
|
ref: prefix[i] + "REF",
|
||||||
|
min_ratio: prefix[i] + "FM_RAT",
|
||||||
|
harmonics: prefix[i] + "HMNCS",
|
||||||
|
options: prefix[i] + "OPTS"}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function HNotch_param_read() {
|
||||||
|
const HNotch_params = get_HNotch_param_names("INS_HNTCH_")
|
||||||
|
|
||||||
|
for (let i = 0; i < HNotch_params.length; i++) {
|
||||||
|
// Enable all params in group if enable is set
|
||||||
|
const enable_input = parseFloat(document.getElementById(HNotch_params[i].enable).value) > 0
|
||||||
|
for (const [key, value] of Object.entries(HNotch_params[i])) {
|
||||||
|
if (key != "enable") {
|
||||||
|
document.getElementById(value).disabled = !enable_input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load values into HNotch object
|
||||||
|
for (let i = 0; i < HNotch_params.length; i++) {
|
||||||
|
HNotch_setup[i] = []
|
||||||
|
for (const [key, value] of Object.entries(HNotch_params[i])) {
|
||||||
|
HNotch_setup[i][key] = parseFloat(document.getElementById(value).value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var Gyro_batch
|
var Gyro_batch
|
||||||
|
var tracking_methods
|
||||||
|
var HNotch_setup = []
|
||||||
function load(log_file) {
|
function load(log_file) {
|
||||||
|
|
||||||
const start = performance.now()
|
const start = performance.now()
|
||||||
|
|
||||||
// Clear and reset state
|
|
||||||
var log = new DataflashParser()
|
var log = new DataflashParser()
|
||||||
log.processData(log_file)
|
log.processData(log_file)
|
||||||
|
|
||||||
|
@ -622,9 +1020,6 @@ function load(log_file) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup/reset plot and options
|
|
||||||
reset()
|
|
||||||
|
|
||||||
log.parseAtOffset('PARM')
|
log.parseAtOffset('PARM')
|
||||||
|
|
||||||
// Try and decode device IDs
|
// Try and decode device IDs
|
||||||
|
@ -632,7 +1027,7 @@ function load(log_file) {
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
const ID_param = i == 0 ? "INS_GYR_ID" : "INS_GYR" + (i + 1) + "_ID"
|
const ID_param = i == 0 ? "INS_GYR_ID" : "INS_GYR" + (i + 1) + "_ID"
|
||||||
const ID = get_param_value(log.messages.PARM, ID_param)
|
const ID = get_param_value(log.messages.PARM, ID_param)
|
||||||
if (ID != null) {
|
if ((ID != null) && (ID > 0)) {
|
||||||
const decoded = decode_devid(ID, DEVICE_TYPE_IMU)
|
const decoded = decode_devid(ID, DEVICE_TYPE_IMU)
|
||||||
if (decoded != null) {
|
if (decoded != null) {
|
||||||
document.getElementById("Gyro" + i + "_info").innerHTML = decoded.name + " via " + decoded.bus_type
|
document.getElementById("Gyro" + i + "_info").innerHTML = decoded.name + " via " + decoded.bus_type
|
||||||
|
@ -663,6 +1058,31 @@ function load(log_file) {
|
||||||
// setup/reset plot and options
|
// setup/reset plot and options
|
||||||
reset()
|
reset()
|
||||||
|
|
||||||
|
|
||||||
|
// Load potential sources of notch tracking targets
|
||||||
|
tracking_methods = [new StaticTarget(),
|
||||||
|
new ThrottleTarget(log),
|
||||||
|
new RPMTarget(log, 1, 2),
|
||||||
|
new ESCTarget(log),
|
||||||
|
new FFTTarget(log),
|
||||||
|
new RPMTarget(log, 2, 5)]
|
||||||
|
|
||||||
|
// Read from log into HTML box
|
||||||
|
const HNotch_params = get_HNotch_param_names()
|
||||||
|
for (let i = 0; i < HNotch_params.length; i++) {
|
||||||
|
for (const param of Object.values(HNotch_params[i])) {
|
||||||
|
const value = get_param_value(log.messages.PARM, param)
|
||||||
|
if (value != null) {
|
||||||
|
document.getElementById(param).value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Allow enable values to be changed
|
||||||
|
document.getElementById(HNotch_params[i].enable).disabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load notch params
|
||||||
|
HNotch_param_read()
|
||||||
|
|
||||||
// Update ranges of start and end time
|
// Update ranges of start and end time
|
||||||
var start_time
|
var start_time
|
||||||
var end_time
|
var end_time
|
||||||
|
|
|
@ -15,6 +15,19 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.plotly-notifier {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.parameter_input_label {
|
||||||
|
display: inline-block;
|
||||||
|
width: 160px;
|
||||||
|
text-align: right;
|
||||||
|
margin:5px 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 30px;"></td>
|
<td style="width: 30px;"></td>
|
||||||
|
@ -210,7 +223,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 60px;"></td>
|
<td style="width: 60px;"></td>
|
||||||
<td>
|
<td>
|
||||||
<fieldset style="width:300px">
|
<fieldset style="width:300px;height:350px">
|
||||||
<legend>Spectrogram Options</legend>
|
<legend>Spectrogram Options</legend>
|
||||||
<p>
|
<p>
|
||||||
<fieldset style="width:300px">
|
<fieldset style="width:300px">
|
||||||
|
@ -248,9 +261,74 @@
|
||||||
<label for="SpecGyroAxisZ">Z</label>
|
<label for="SpecGyroAxisZ">Z</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</p>
|
</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<fieldset style="width:300px;height:350px">
|
||||||
|
<legend>First Notch Filter</legend>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_ENABLE">INS_HNTCH_ENABLE</label>
|
||||||
|
<input id="INS_HNTCH_ENABLE" name="INS_HNTCH_ENABLE" type="number" step="1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_MODE">INS_HNTCH_MODE</label>
|
||||||
|
<input id="INS_HNTCH_MODE" name="INS_HNTCH_MODE" type="number" step="1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_FREQ">INS_HNTCH_FREQ</label>
|
||||||
|
<input id="INS_HNTCH_FREQ" name="INS_HNTCH_FREQ" type="number" step="0.1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_REF">INS_HNTCH_REF</label>
|
||||||
|
<input id="INS_HNTCH_REF" name="INS_HNTCH_REF" type="number" step="0.01" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_FM_RAT">INS_HNTCH_FM_RAT</label>
|
||||||
|
<input id="INS_HNTCH_FM_RAT" name="INS_HNTCH_FM_RAT" type="number" step="0.01" value="1.0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_HMNCS">INS_HNTCH_HMNCS</label>
|
||||||
|
<input id="INS_HNTCH_HMNCS" name="INS_HNTCH_HMNCS" type="number" step="1" value="1" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTCH_OPTS">INS_HNTCH_OPTS</label>
|
||||||
|
<input id="INS_HNTCH_OPTS" name="INS_HNTCH_OPTS" type="number" step="1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<fieldset style="width:300px;height:350px">
|
||||||
|
<legend>Second Notch Filter</legend>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_ENABLE">INS_HNTC2_ENABLE</label>
|
||||||
|
<input id="INS_HNTC2_ENABLE" name="INS_HNTC2_ENABLE" type="number" step="1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_MODE">INS_HNTC2_MODE</label>
|
||||||
|
<input id="INS_HNTC2_MODE" name="INS_HNTC2_MODE" type="number" step="1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_FREQ">INS_HNTC2_FREQ</label>
|
||||||
|
<input id="INS_HNTC2_FREQ" name="INS_HNTC2_FREQ" type="number" step="0.1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_REF">INS_HNTC2_REF</label>
|
||||||
|
<input id="INS_HNTC2_REF" name="INS_HNTC2_REF" type="number" step="0.01" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_FM_RAT">INS_HNTC2_FM_RAT</label>
|
||||||
|
<input id="INS_HNTC2_FM_RAT" name="INS_HNTC2_FM_RAT" type="number" step="0.01" value="1.0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_HMNCS">INS_HNTC2_HMNCS</label>
|
||||||
|
<input id="INS_HNTC2_HMNCS" name="INS_HNTC2_HMNCS" type="number" step="1" value="1" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label class="parameter_input_label" for="INS_HNTC2_OPTS">INS_HNTC2_OPTS</label>
|
||||||
|
<input id="INS_HNTC2_OPTS" name="INS_HNTC2_OPTS" type="number" step="1" value="0" onchange="HNotch_param_read(); redraw_Spectrogram();" style="width: 100px" disabled/>
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue