Tools: autotest: Web: remove tools (now here : https://github.com/ArduPilot/WebTools)
This commit is contained in:
parent
f77635a5a6
commit
4d72a86032
@ -1,154 +0,0 @@
|
||||
/*
|
||||
Translated from Tools/scripts/decode_devid.py
|
||||
*/
|
||||
|
||||
const DEVICE_TYPE_COMPASS = 0
|
||||
const DEVICE_TYPE_IMU = 1
|
||||
const DEVICE_TYPE_BARO = 2
|
||||
const DEVICE_TYPE_AIRSPEED = 3
|
||||
|
||||
function decode_devid(ID, type) {
|
||||
|
||||
const bus_type = ID & 0x07
|
||||
const bus = (ID>>3) & 0x1F
|
||||
const address = (ID>>8) & 0xFF
|
||||
const devtype = (ID>>16)
|
||||
|
||||
bustypes = {
|
||||
1: "I2C",
|
||||
2: "SPI",
|
||||
3: "DRONECAN",
|
||||
4: "SITL",
|
||||
5: "MSP",
|
||||
6: "SERIAL",
|
||||
}
|
||||
|
||||
compass_types = {
|
||||
0x01 : "HMC5883_OLD",
|
||||
0x07 : "HMC5883",
|
||||
0x02 : "LSM303D",
|
||||
0x04 : "AK8963 ",
|
||||
0x05 : "BMM150 ",
|
||||
0x06 : "LSM9DS1",
|
||||
0x08 : "LIS3MDL",
|
||||
0x09 : "AK09916",
|
||||
0x0A : "IST8310",
|
||||
0x0B : "ICM20948",
|
||||
0x0C : "MMC3416",
|
||||
0x0D : "QMC5883L",
|
||||
0x0E : "MAG3110",
|
||||
0x0F : "SITL",
|
||||
0x10 : "IST8308",
|
||||
0x11 : "RM3100_OLD",
|
||||
0x12 : "RM3100",
|
||||
0x13 : "MMC5883",
|
||||
0x14 : "AK09918",
|
||||
}
|
||||
|
||||
imu_types = {
|
||||
0x09 : "BMI160",
|
||||
0x10 : "L3G4200D",
|
||||
0x11 : "ACC_LSM303D",
|
||||
0x12 : "ACC_BMA180",
|
||||
0x13 : "ACC_MPU6000",
|
||||
0x16 : "ACC_MPU9250",
|
||||
0x17 : "ACC_IIS328DQ",
|
||||
0x21 : "GYR_MPU6000",
|
||||
0x22 : "GYR_L3GD20",
|
||||
0x24 : "GYR_MPU9250",
|
||||
0x25 : "GYR_I3G4250D",
|
||||
0x26 : "GYR_LSM9DS1",
|
||||
0x27 : "ICM20789",
|
||||
0x28 : "ICM20689",
|
||||
0x29 : "BMI055",
|
||||
0x2A : "SITL",
|
||||
0x2B : "BMI088",
|
||||
0x2C : "ICM20948",
|
||||
0x2D : "ICM20648",
|
||||
0x2E : "ICM20649",
|
||||
0x2F : "ICM20602",
|
||||
0x30 : "ICM20601",
|
||||
0x31 : "ADIS1647x",
|
||||
0x32 : "SERIAL",
|
||||
0x33 : "ICM40609",
|
||||
0x34 : "ICM42688",
|
||||
0x35 : "ICM42605",
|
||||
0x36 : "ICM40605",
|
||||
0x37 : "IIM42652",
|
||||
0x38 : "BMI270",
|
||||
0x39 : "BMI085",
|
||||
0x3A : "ICM42670",
|
||||
}
|
||||
|
||||
baro_types = {
|
||||
0x01 : "SITL",
|
||||
0x02 : "BMP085",
|
||||
0x03 : "BMP280",
|
||||
0x04 : "BMP388",
|
||||
0x05 : "DPS280",
|
||||
0x06 : "DPS310",
|
||||
0x07 : "FBM320",
|
||||
0x08 : "ICM20789",
|
||||
0x09 : "KELLERLD",
|
||||
0x0A : "LPS2XH",
|
||||
0x0B : "MS5611",
|
||||
0x0C : "SPL06",
|
||||
0x0D : "DRONECAN",
|
||||
0x0E : "MSP",
|
||||
0x0F : "ICP101XX",
|
||||
0x10 : "ICP201XX",
|
||||
0x11 : "MS5607",
|
||||
0x12 : "MS5837",
|
||||
0x13 : "MS5637",
|
||||
0x14 : "BMP390",
|
||||
}
|
||||
|
||||
airspeed_types = {
|
||||
0x01 : "SITL",
|
||||
0x02 : "MS4525",
|
||||
0x03 : "MS5525",
|
||||
0x04 : "DLVR",
|
||||
0x05 : "MSP",
|
||||
0x06 : "SDP3X",
|
||||
0x07 : "DRONECAN",
|
||||
0x08 : "ANALOG",
|
||||
0x09 : "NMEA",
|
||||
0x0A : "ASP5033",
|
||||
}
|
||||
|
||||
function get(lookup, index) {
|
||||
if (lookup[index] != null) {
|
||||
return lookup[index]
|
||||
}
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
var name
|
||||
switch (type) {
|
||||
case DEVICE_TYPE_COMPASS:
|
||||
name = "Compass: " + get(compass_types, devtype)
|
||||
break
|
||||
case DEVICE_TYPE_IMU:
|
||||
name = "IMU: " + get(imu_types, devtype)
|
||||
break
|
||||
case DEVICE_TYPE_BARO:
|
||||
name = "Baro: " + get(baro_types, devtype)
|
||||
break
|
||||
case DEVICE_TYPE_AIRSPEED:
|
||||
name = "Airspeed: " + get(airspeed_types, devtype)
|
||||
break
|
||||
default:
|
||||
console.error("Unknown type");
|
||||
return
|
||||
}
|
||||
|
||||
const bus_type_string = get(bustypes, bus_type)
|
||||
|
||||
if (bus_type == 3) {
|
||||
// dronecan devtype represents sensor_id
|
||||
return { bus_type: bus_type_string, bus: bus, address: address, sensor_id: devtype-1, name: name }
|
||||
}
|
||||
|
||||
return { bus_type: bus_type_string, bus: bus, address: address, devtype: devtype, name: name }
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +0,0 @@
|
||||
Test with `python -m http.server --bind 127.0.0.1`
|
||||
|
||||
Uses log parser from https://github.com/Williangalvani/JsDataflashParser
|
||||
|
||||
WIP!
|
||||
|
@ -1,354 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ArduPilot Filter Review Tool</title>
|
||||
<script src='https://cdn.plot.ly/plotly-2.20.0.min.js'></script>
|
||||
<script src="https://unpkg.com/mathjs/lib/browser/math.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"> </script>
|
||||
<script type="text/javascript" src="parser.js"></script>
|
||||
<script type="text/javascript" src="DecodeDevID.js"></script>
|
||||
|
||||
</head>
|
||||
<a href="https://ardupilot.org"><img src="logo.png"></a>
|
||||
<h1>ArduPilot Filter Review Tool</h1>
|
||||
|
||||
<body>
|
||||
|
||||
<style>
|
||||
div.plotly-notifier {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
label.parameter_input_label {
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
text-align: right;
|
||||
margin:5px 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td style="width: 30px;"></td>
|
||||
<td>
|
||||
<fieldset style="width:1100px">
|
||||
<legend>Setup</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<fieldset style="width:150px;height:80px">
|
||||
<legend>Amplitude scale</legend>
|
||||
<input type="radio" id="ScaleLog" name="Scale" checked>
|
||||
<label for="LogScale">dB</label><br>
|
||||
<input type="radio" id="ScaleLinear" name="Scale">
|
||||
<label for="LinearScale">Linear</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:200px;height:80px">
|
||||
<legend>Spectrum scale</legend>
|
||||
<input type="radio" id="SpectrumLinear" name="SpectrumScale" checked>
|
||||
<label for="SpectrumLinear">Linear</label><br>
|
||||
<input type="radio" id="SpectrumPSD" name="SpectrumScale">
|
||||
<label for="SpectrumPSD">Power Spectral Density</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:150px;height:80px">
|
||||
<legend>Frequency scale</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" id="freq_ScaleLinear" name="feq_scale" checked>
|
||||
<label for="LinearScale">Linear</label><br>
|
||||
<input type="radio" id="freq_ScaleLog" name="feq_scale">
|
||||
<label for="LogScale">Log</label><br>
|
||||
</td>
|
||||
<td>
|
||||
<input type="radio" id="freq_Scale_Hz" name="feq_unit" checked>
|
||||
<label for="Scale_unit_Hz">Hz</label><br>
|
||||
<input type="radio" id="freq_Scale_RPM" name="feq_unit">
|
||||
<label for="Scale_unit_RPM">RPM</label><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:200px;height:80px">
|
||||
<legend>FFT Settings</legend>
|
||||
<label for="FFTWindow">Windows per batch</label>
|
||||
<input id="FFTWindow" name="FFTWindow" type="number" min="1" step="1" value="1" onchange="clear_calculation()" style="width:50px"/>
|
||||
<br><br>
|
||||
<label id="FFTWindowInfo"></label>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:200px;height:80px">
|
||||
<legend>Analysis time</legend>
|
||||
<label for="TimeStart">Start</label>
|
||||
<input id="TimeStart" name="TimeStart" type="number" min="0" step="1" value="0" onchange="" style="width:50px" disabled/>
|
||||
s<br><br>
|
||||
<label for="TimeEnd">End</label>
|
||||
<input id="TimeEnd" name="TimeEnd" type="number" min="0" step="1" value="0" onchange="" style="width:50px" disabled/>
|
||||
s
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
Bin log:
|
||||
<input id="fileItem" type="file" accept=".bin" onchange="readFile(this)">
|
||||
<input type="button" id="calculate" value="Calculate" onclick="re_calc()" disabled>
|
||||
</p>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<div id="FFTPlot" style="width:1200px;height:450px"></div>
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td style="width: 60px;"></td>
|
||||
<td>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Gyro 1</legend>
|
||||
<label id="Gyro0_info"><br></label>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Pre-filter</legend>
|
||||
<input type="checkbox" id="Gyro0PreX" name="Gyro0PreX" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro0PreX">X</label>
|
||||
|
||||
<input type="checkbox" id="Gyro0PreY" name="Gyro0PreY" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro0PreY">Y</label>
|
||||
|
||||
<input type="checkbox" id="Gyro0PreZ" name="Gyro0PreZ" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro0PreZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Post-filter</legend>
|
||||
<input type="checkbox" id="Gyro0PostX" name="Gyro0PostX" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro0PostX">X</label>
|
||||
|
||||
<input type="checkbox" id="Gyro0PostY" name="Gyro0PostY" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro0PostY">Y</label>
|
||||
|
||||
<input type="checkbox" id="Gyro0PostZ" name="Gyro0PostZ" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro0PostZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<label id="Gyro0_FFT_info"><br><br><br></label>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Gyro 2</legend>
|
||||
<label id="Gyro1_info"><br></label>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Pre-filter</legend>
|
||||
<input type="checkbox" id="Gyro1PreX" name="Gyro1PreX" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro1PreX">X</label>
|
||||
|
||||
<input type="checkbox" id="Gyro1PreY" name="Gyro1PreY" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro1PreY">Y</label>
|
||||
|
||||
<input type="checkbox" id="Gyro1PreZ" name="Gyro1PreZ" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro1PreZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Post-filter</legend>
|
||||
<input type="checkbox" id="Gyro1PostX" name="Gyro1PostX" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro1PostX">X</label>
|
||||
|
||||
<input type="checkbox" id="Gyro1PostY" name="Gyro1PostY" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro1PostY">Y</label>
|
||||
|
||||
<input type="checkbox" id="Gyro1PostZ" name="Gyro1PostZ" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro1PostZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<label id="Gyro1_FFT_info"><br><br><br></label>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Gyro 3</legend>
|
||||
<label id="Gyro2_info"><br></label>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Pre-filter</legend>
|
||||
<input type="checkbox" id="Gyro2PreX" name="Gyro2PreX" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro2PreX">X</label>
|
||||
|
||||
<input type="checkbox" id="Gyro2PreY" name="Gyro2PreY" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro2PreY">Y</label>
|
||||
|
||||
<input type="checkbox" id="Gyro2PreZ" name="Gyro2PreZ" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro2PreZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Post-filter</legend>
|
||||
<input type="checkbox" id="Gyro2PostX" name="Gyro2PostX" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro2PostX">X</label>
|
||||
|
||||
<input type="checkbox" id="Gyro2PostY" name="Gyro2PostY" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro2PostY">Y</label>
|
||||
|
||||
<input type="checkbox" id="Gyro2PostZ" name="Gyro2PostZ" onchange="update_hidden(this)" checked disabled>
|
||||
<label for="Gyro2PostZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<label id="Gyro2_FFT_info"><br><br><br></label>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<p>
|
||||
<div id="Spectrogram" style="width:1200px;height:450px"></div>
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td style="width: 60px;"></td>
|
||||
<td>
|
||||
<fieldset style="width:300px;height:350px">
|
||||
<legend>Spectrogram Options</legend>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Gyro instance</legend>
|
||||
<input type="radio" id="SpecGyroInst0" name="SpecGyroInst" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroInst0">1</label>
|
||||
|
||||
<input type="radio" id="SpecGyroInst1" name="SpecGyroInst" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroInst1">2</label>
|
||||
|
||||
<input type="radio" id="SpecGyroInst2" name="SpecGyroInst" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroInst2">3</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Filtering</legend>
|
||||
<input type="radio" id="SpecGyroPre" name="SpecGyroPrePost" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroPre">Pre-filter</label>
|
||||
|
||||
<input type="radio" id="SpecGyroPost" name="SpecGyroPrePost" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroPost">Post-filter</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
<p>
|
||||
<fieldset style="width:300px">
|
||||
<legend>Axis</legend>
|
||||
<input type="radio" id="SpecGyroAxisX" name="SpecGyroAxis" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroAxisX">X</label>
|
||||
|
||||
<input type="radio" id="SpecGyroAxisY" name="SpecGyroAxis" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroAxisY">Y</label>
|
||||
|
||||
<input type="radio" id="SpecGyroAxisZ" name="SpecGyroAxis" onchange="redraw_Spectrogram()" disabled>
|
||||
<label for="SpecGyroAxisZ">Z</label>
|
||||
</fieldset>
|
||||
</p>
|
||||
</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>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<script type="text/javascript" src="FilterReview.js"></script>
|
||||
<script>
|
||||
function readFile(e) {
|
||||
const file = e.files[0]
|
||||
if (file == null) {
|
||||
return
|
||||
}
|
||||
let reader = new FileReader()
|
||||
reader.onload = function (e) {
|
||||
load(reader.result)
|
||||
}
|
||||
reader.readAsArrayBuffer(file)
|
||||
}
|
||||
|
||||
</script>
|
@ -1,882 +0,0 @@
|
||||
const MAV_TYPE_GENERIC = 0 // Generic micro air vehicle.
|
||||
const MAV_TYPE_FIXED_WING = 1 // Fixed wing aircraft.
|
||||
const MAV_TYPE_QUADROTOR = 2 // Quadrotor
|
||||
const MAV_TYPE_COAXIAL = 3 // Coaxial helicopter
|
||||
const MAV_TYPE_HELICOPTER = 4 // Normal helicopter with tail rotor.
|
||||
const MAV_TYPE_ANTENNA_TRACKER = 5 // Ground installation
|
||||
const MAV_TYPE_GCS = 6 // Operator control unit / ground control station
|
||||
const MAV_TYPE_AIRSHIP = 7 // Airship, controlled
|
||||
const MAV_TYPE_FREE_BALLOON = 8 // Free balloon, uncontrolled
|
||||
const MAV_TYPE_ROCKET = 9 // Rocket
|
||||
const MAV_TYPE_GROUND_ROVER = 10 // Ground rover
|
||||
const MAV_TYPE_SURFACE_BOAT = 11 // Surface vessel, boat, ship
|
||||
const MAV_TYPE_SUBMARINE = 12 // Submarine
|
||||
const MAV_TYPE_HEXAROTOR = 13 // Hexarotor
|
||||
const MAV_TYPE_OCTOROTOR = 14 // Octorotor
|
||||
const MAV_TYPE_TRICOPTER = 15 // Tricopter
|
||||
const MAV_TYPE_FLAPPING_WING = 16 // Flapping wing
|
||||
const MAV_TYPE_KITE = 17 // Kite
|
||||
const MAV_TYPE_ONBOARD_CONTROLLER = 18 // Onboard companion controller
|
||||
const MAV_TYPE_VTOL_DUOROTOR = 19 // Two-rotor VTOL using control surfaces in vertical operation in addition. Tailsitter.
|
||||
const MAV_TYPE_VTOL_QUADROTOR = 20 // Quad-rotor VTOL using a V-shaped quad config in vertical operation.
|
||||
// Tailsitter.
|
||||
const MAV_TYPE_VTOL_TILTROTOR = 21 // Tiltrotor VTOL
|
||||
const MAV_TYPE_VTOL_RESERVED2 = 22 // VTOL reserved 2
|
||||
const MAV_TYPE_VTOL_RESERVED3 = 23 // VTOL reserved 3
|
||||
const MAV_TYPE_VTOL_RESERVED4 = 24 // VTOL reserved 4
|
||||
const MAV_TYPE_VTOL_RESERVED5 = 25 // VTOL reserved 5
|
||||
const MAV_TYPE_GIMBAL = 26 // Onboard gimbal
|
||||
const MAV_TYPE_ADSB = 27 // Onboard ADSB peripheral
|
||||
const MAV_TYPE_PARAFOIL = 28 // Steerable, nonrigid airfoil
|
||||
const MAV_TYPE_DODECAROTOR = 29 // Dodecarotor
|
||||
const MAV_TYPE_CAMERA = 30 // Camera
|
||||
const MAV_TYPE_CHARGING_STATION = 31 // Charging station
|
||||
const MAV_TYPE_FLARM = 32 // Onboard FLARM collision avoidance system
|
||||
const MAV_TYPE_ENUM_END = 33 //
|
||||
|
||||
|
||||
const modeMappingApm = {
|
||||
0: 'MANUAL',
|
||||
1: 'CIRCLE',
|
||||
2: 'STABILIZE',
|
||||
3: 'TRAINING',
|
||||
4: 'ACRO',
|
||||
5: 'FBWA',
|
||||
6: 'FBWB',
|
||||
7: 'CRUISE',
|
||||
8: 'AUTOTUNE',
|
||||
10: 'AUTO',
|
||||
11: 'RTL',
|
||||
12: 'LOITER',
|
||||
13: 'TAKEOFF',
|
||||
14: 'AVOID_ADSB',
|
||||
15: 'GUIDED',
|
||||
16: 'INITIALISING',
|
||||
17: 'QSTABILIZE',
|
||||
18: 'QHOVER',
|
||||
19: 'QLOITER',
|
||||
20: 'QLAND',
|
||||
21: 'QRTL',
|
||||
22: 'QAUTOTUNE',
|
||||
23: 'QACRO',
|
||||
24: 'THERMAL'
|
||||
}
|
||||
const modeMappingAcm = {
|
||||
0: 'STABILIZE',
|
||||
1: 'ACRO',
|
||||
2: 'ALT_HOLD',
|
||||
3: 'AUTO',
|
||||
4: 'GUIDED',
|
||||
5: 'LOITER',
|
||||
6: 'RTL',
|
||||
7: 'CIRCLE',
|
||||
9: 'LAND',
|
||||
11: 'DRIFT',
|
||||
13: 'SPORT',
|
||||
14: 'FLIP',
|
||||
15: 'AUTOTUNE',
|
||||
16: 'POSHOLD',
|
||||
17: 'BRAKE',
|
||||
18: 'THROW',
|
||||
19: 'AVOID_ADSB',
|
||||
20: 'GUIDED_NOGPS',
|
||||
21: 'SMART_RTL',
|
||||
22: 'FLOWHOLD',
|
||||
23: 'FOLLOW',
|
||||
24: 'ZIGZAG',
|
||||
25: 'SYSTEMID',
|
||||
26: 'AUTOROTATE'
|
||||
}
|
||||
const modeMappingRover = {
|
||||
0: 'MANUAL',
|
||||
1: 'ACRO',
|
||||
3: 'STEERING',
|
||||
4: 'HOLD',
|
||||
5: 'LOITER',
|
||||
6: 'FOLLOW',
|
||||
7: 'SIMPLE',
|
||||
10: 'AUTO',
|
||||
11: 'RTL',
|
||||
12: 'SMART_RTL',
|
||||
15: 'GUIDED',
|
||||
16: 'INITIALISING'
|
||||
}
|
||||
const modeMappingTracker = {
|
||||
0: 'MANUAL',
|
||||
1: 'STOP',
|
||||
2: 'SCAN',
|
||||
3: 'SERVO_TEST',
|
||||
10: 'AUTO',
|
||||
16: 'INITIALISING'
|
||||
}
|
||||
const modeMappingSub = {
|
||||
0: 'STABILIZE',
|
||||
1: 'ACRO',
|
||||
2: 'ALT_HOLD',
|
||||
3: 'AUTO',
|
||||
4: 'GUIDED',
|
||||
7: 'CIRCLE',
|
||||
9: 'SURFACE',
|
||||
16: 'POSHOLD',
|
||||
19: 'MANUAL',
|
||||
20: 'MOTOR_DETECT'
|
||||
}
|
||||
|
||||
|
||||
const multipliers = {
|
||||
'-': 0, // no multiplier e.g. a string
|
||||
'?': 1, // multipliers which haven't been worked out yet....
|
||||
// <leave a gap here, just in case....>
|
||||
'2': 1e2,
|
||||
'1': 1e1,
|
||||
'0': 1e0,
|
||||
'A': 1e-1,
|
||||
'B': 1e-2,
|
||||
'C': 1e-3,
|
||||
'D': 1e-4,
|
||||
'E': 1e-5,
|
||||
'F': 1e-6,
|
||||
'G': 1e-7,
|
||||
// <leave a gap here, just in case....>
|
||||
'!': 3.6, // (ampere*second => milliampere*hour) and (km/h => m/s)
|
||||
'/': 3600 // (ampere*second => ampere*hour)
|
||||
}
|
||||
|
||||
const multipliersTable = {
|
||||
0.000001: 'n',
|
||||
1000: 'M',
|
||||
0.001: 'm'
|
||||
}
|
||||
|
||||
const HEAD1 = 163
|
||||
const HEAD2 = 149
|
||||
|
||||
const units = {
|
||||
'-': '', // no units e.g. Pi, or a string
|
||||
'?': 'UNKNOWN', // Units which haven't been worked out yet....
|
||||
'A': 'A', // Ampere
|
||||
'd': '°', // of the angular variety, -180 to 180
|
||||
'b': 'B', // bytes
|
||||
'k': '°/s', // degrees per second. Degrees are NOT SI, but is some situations more user-friendly than radians
|
||||
'D': '°', // degrees of latitude
|
||||
'e': '°/s/s', // degrees per second per second. Degrees are NOT SI, but is some situations more user-friendly
|
||||
'E': 'rad/s', // radians per second
|
||||
'G': 'Gauss', // Gauss is not an SI unit, but 1 tesla = 10000 gauss so a simple replacement is not possible here
|
||||
'h': '°', // 0.? to 359.?
|
||||
'i': 'A.s', // Ampere second
|
||||
'J': 'W.s', // Joule (Watt second)
|
||||
// { 'l', "l" }, // litres
|
||||
'L': 'rad/s/s', // radians per second per second
|
||||
'm': 'm', // metres
|
||||
'n': 'm/s', // metres per second
|
||||
// { 'N', "N" }, // Newton
|
||||
'o': 'm/s/s', // metres per second per second
|
||||
'O': '°C', // degrees Celsius. Not SI, but Kelvin is too cumbersome for most users
|
||||
'%': '%', // percent
|
||||
'S': 'satellites', // number of satellites
|
||||
's': 's', // seconds
|
||||
'q': 'rpm', // rounds per minute. Not SI, but sometimes more intuitive than Hertz
|
||||
'r': 'rad', // radians
|
||||
'U': '°', // degrees of longitude
|
||||
'u': 'ppm', // pulses per minute
|
||||
'v': 'V', // Volt
|
||||
'P': 'Pa', // Pascal
|
||||
'w': 'Ohm', // Ohm
|
||||
'Y': 'us', // pulse width modulation in microseconds
|
||||
'z': 'Hz', // Hertz
|
||||
'#': 'instance' // instance number for message
|
||||
}
|
||||
|
||||
function getModeMap (mavType) {
|
||||
let map
|
||||
if ([MAV_TYPE_QUADROTOR,
|
||||
MAV_TYPE_HELICOPTER,
|
||||
MAV_TYPE_HEXAROTOR,
|
||||
MAV_TYPE_OCTOROTOR,
|
||||
MAV_TYPE_COAXIAL,
|
||||
MAV_TYPE_TRICOPTER].includes(mavType)) {
|
||||
map = modeMappingAcm
|
||||
}
|
||||
if (mavType === MAV_TYPE_FIXED_WING) {
|
||||
map = modeMappingApm
|
||||
}
|
||||
if (mavType === MAV_TYPE_GROUND_ROVER) {
|
||||
map = modeMappingRover
|
||||
}
|
||||
if (mavType === MAV_TYPE_ANTENNA_TRACKER) {
|
||||
map = modeMappingTracker
|
||||
}
|
||||
if (mavType === MAV_TYPE_SUBMARINE) {
|
||||
map = modeMappingSub
|
||||
}
|
||||
if (map == null) {
|
||||
return null
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
function assignColumn (obj) {
|
||||
var ArrayOfString = obj.split(',')
|
||||
return ArrayOfString
|
||||
}
|
||||
|
||||
// Converts from degrees to radians.
|
||||
Math.radians = function (degrees) {
|
||||
return degrees * Math.PI / 180
|
||||
}
|
||||
|
||||
// Converts from radians to degrees.
|
||||
Math.degrees = function (radians) {
|
||||
return radians * 180 / Math.PI
|
||||
}
|
||||
|
||||
class DataflashParser {
|
||||
constructor () {
|
||||
this.time = null
|
||||
this.timebase = null
|
||||
this.buffer = null
|
||||
this.data = null
|
||||
this.FMT = []
|
||||
this.FMT[128] = {
|
||||
'Type': '128',
|
||||
'length': '89',
|
||||
'Name': 'FMT',
|
||||
'Format': 'BBnNZ',
|
||||
'Columns': 'Type,Length,Name,Format,Columns'
|
||||
}
|
||||
this.offset = 0
|
||||
this.msgType = []
|
||||
this.offsetArray = []
|
||||
this.totalSize = null
|
||||
this.messages = {}
|
||||
this.lastPercentage = 0
|
||||
this.sent = false
|
||||
this.maxPercentageInterval = 0.05
|
||||
this.messageTypes = {}
|
||||
this.alreadyParsed = []
|
||||
}
|
||||
|
||||
FORMAT_TO_STRUCT (obj) {
|
||||
var temp
|
||||
var dict = {
|
||||
name: obj.Name,
|
||||
fieldnames: obj.Columns.split(',')
|
||||
}
|
||||
|
||||
let column = assignColumn(obj.Columns)
|
||||
let low
|
||||
let n
|
||||
for (let i = 0; i < obj.Format.length; i++) {
|
||||
temp = obj.Format.charAt(i)
|
||||
switch (temp) {
|
||||
case 'a': // int16_t[32]
|
||||
dict[column[i]] = []
|
||||
for (let j = 0; j < 32; j++) {
|
||||
dict[column[i]][j] = this.data.getInt16(this.offset, true)
|
||||
this.offset += 2
|
||||
}
|
||||
break
|
||||
case 'b':
|
||||
dict[column[i]] = this.data.getInt8(this.offset)
|
||||
this.offset += 1
|
||||
break
|
||||
case 'B':
|
||||
dict[column[i]] = this.data.getUint8(this.offset)
|
||||
this.offset += 1
|
||||
break
|
||||
case 'h':
|
||||
dict[column[i]] = this.data.getInt16(this.offset, true)
|
||||
this.offset += 2
|
||||
break
|
||||
case 'H':
|
||||
dict[column[i]] = this.data.getUint16(this.offset, true)
|
||||
this.offset += 2
|
||||
break
|
||||
case 'i':
|
||||
dict[column[i]] = this.data.getInt32(this.offset, true)
|
||||
this.offset += 4
|
||||
break
|
||||
case 'I':
|
||||
dict[column[i]] = this.data.getUint32(this.offset, true)
|
||||
this.offset += 4
|
||||
break
|
||||
case 'f':
|
||||
dict[column[i]] = this.data.getFloat32(this.offset, true)
|
||||
this.offset += 4
|
||||
break
|
||||
case 'd':
|
||||
dict[column[i]] = this.data.getFloat64(this.offset, true)
|
||||
this.offset += 8
|
||||
break
|
||||
case 'Q':
|
||||
low = this.data.getUint32(this.offset, true)
|
||||
this.offset += 4
|
||||
n = this.data.getUint32(this.offset, true) * 4294967296.0 + low
|
||||
if (low < 0) n += 4294967296
|
||||
dict[column[i]] = n
|
||||
this.offset += 4
|
||||
break
|
||||
case 'q':
|
||||
low = this.data.getInt32(this.offset, true)
|
||||
this.offset += 4
|
||||
n = this.data.getInt32(this.offset, true) * 4294967296.0 + low
|
||||
if (low < 0) n += 4294967296
|
||||
dict[column[i]] = n
|
||||
this.offset += 4
|
||||
break
|
||||
case 'n':
|
||||
// TODO: fix these regex and unsilent linter
|
||||
// eslint-disable-next-line
|
||||
dict[column[i]] = String.fromCharCode.apply(null, new Uint8Array(this.buffer, this.offset, 4)).replace(/\x00+$/g, '')
|
||||
this.offset += 4
|
||||
break
|
||||
case 'N':
|
||||
// eslint-disable-next-line
|
||||
dict[column[i]] = String.fromCharCode.apply(null, new Uint8Array(this.buffer, this.offset, 16)).replace(/\x00+$/g, '')
|
||||
this.offset += 16
|
||||
break
|
||||
case 'Z':
|
||||
// eslint-disable-next-line
|
||||
dict[column[i]] = String.fromCharCode.apply(null, new Uint8Array(this.buffer, this.offset, 64)).replace(/\x00+$/g, '')
|
||||
this.offset += 64
|
||||
break
|
||||
case 'c':
|
||||
// this.this.data.setInt16(offset,true);
|
||||
dict[column[i]] = this.data.getInt16(this.offset, true) / 100
|
||||
this.offset += 2
|
||||
break
|
||||
case 'C':
|
||||
// this.data.setUint16(offset,true);
|
||||
dict[column[i]] = this.data.getUint16(this.offset, true) / 100
|
||||
this.offset += 2
|
||||
break
|
||||
case 'E':
|
||||
// this.data.setUint32(offset,true);
|
||||
dict[column[i]] = this.data.getUint32(this.offset, true) / 100
|
||||
this.offset += 4
|
||||
break
|
||||
case 'e':
|
||||
// this.data.setInt32(offset,true);
|
||||
dict[column[i]] = this.data.getInt32(this.offset, true) / 100
|
||||
this.offset += 4
|
||||
break
|
||||
case 'L':
|
||||
// this.data.setInt32(offset,true);
|
||||
dict[column[i]] = this.data.getInt32(this.offset, true)
|
||||
this.offset += 4
|
||||
break
|
||||
case 'M':
|
||||
// this.data.setInt32(offset,true);
|
||||
dict[column[i]] = this.data.getUint8(this.offset)
|
||||
this.offset += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
return dict
|
||||
}
|
||||
|
||||
gpstimetoTime (week, msec) {
|
||||
let epoch = 86400 * (10 * 365 + (1980 - 1969) / 4 + 1 + 6 - 2)
|
||||
return epoch + 86400 * 7 * week + msec * 0.001 - 15
|
||||
}
|
||||
|
||||
setTimeBase (base) {
|
||||
this.timebase = base
|
||||
}
|
||||
|
||||
findTimeBase (gps) {
|
||||
const temp = this.gpstimetoTime(parseInt(gps['GWk']), parseInt(gps['GMS']))
|
||||
this.setTimeBase(parseInt(temp - gps['TimeUS'] * 0.000001))
|
||||
}
|
||||
|
||||
getMsgType (element) {
|
||||
for (let i = 0; i < this.FMT.length; i++) {
|
||||
if (this.FMT[i] != null) {
|
||||
// eslint-disable-next-line
|
||||
if (this.FMT[i].Name == element) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMessage (message) {
|
||||
if (this.totalSize == null) { // for percentage calculation
|
||||
this.totalSize = this.buffer.byteLength
|
||||
}
|
||||
if (message.name in this.messages) {
|
||||
this.messages[message.name].push(this.fixData(message))
|
||||
} else {
|
||||
this.messages[message.name] = [this.fixData(message)]
|
||||
}
|
||||
let percentage = 100 * this.offset / this.totalSize
|
||||
if ((percentage - this.lastPercentage) > this.maxPercentageInterval) {
|
||||
self.postMessage({percentage: percentage})
|
||||
this.lastPercentage = percentage
|
||||
}
|
||||
}
|
||||
|
||||
messageHasInstances (name) {
|
||||
let type = this.FMT.find(msg => msg !== undefined && msg.Name === name)
|
||||
return type !== undefined && type.units !== undefined && type.units.includes('instance')
|
||||
}
|
||||
|
||||
getInstancesFieldName (name) {
|
||||
let type = this.FMT.find(msg => msg !== undefined && msg.Name === name)
|
||||
if (type.units === undefined) {
|
||||
return null
|
||||
}
|
||||
return type.Columns.split(',')[type.units.indexOf('instance')]
|
||||
}
|
||||
|
||||
// Next three functions are used for transfering data on postmessage, instead of cloning
|
||||
isTypedArray (arr) {
|
||||
return ArrayBuffer.isView(arr) && !(arr instanceof DataView)
|
||||
}
|
||||
|
||||
getType (arr) {
|
||||
return this.isTypedArray(arr) && arr.constructor.name
|
||||
}
|
||||
|
||||
postData (data) {
|
||||
data['dataType'] = {}
|
||||
const transferables = []
|
||||
for (let field of Object.keys(data.messageList)) {
|
||||
const arrayType = this.getType(data.messageList[field])
|
||||
if (arrayType) {
|
||||
transferables.push(data.messageList[field].buffer)
|
||||
}
|
||||
// Apparently it is magically decoded on the other end, no need for metadata
|
||||
// data['dataType'][field] = arrayType
|
||||
}
|
||||
self.postMessage(data, transferables)
|
||||
}
|
||||
|
||||
parseAtOffset (name) {
|
||||
let type = this.getMsgType(name)
|
||||
var parsed = []
|
||||
for (var i = 0; i < this.msgType.length; i++) {
|
||||
if (type === this.msgType[i]) {
|
||||
this.offset = this.offsetArray[i]
|
||||
try {
|
||||
let temp = this.FORMAT_TO_STRUCT(this.FMT[this.msgType[i]])
|
||||
if (temp['name'] != null) {
|
||||
parsed.push(this.fixData(temp))
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('reached log end?')
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
if (i % 100000 === 0) {
|
||||
let perc = 100 * i / this.msgType.length
|
||||
self.postMessage({percentage: perc})
|
||||
}
|
||||
}
|
||||
delete this.messages[name]
|
||||
this.messages[name] = parsed
|
||||
|
||||
self.postMessage({percentage: 100})
|
||||
console.log(name, this.messageHasInstances(name) ? 'has instances' : 'has no instances')
|
||||
if (parsed.length && this.messageHasInstances(name)) {
|
||||
let instanceField = this.getInstancesFieldName(name)
|
||||
let instances = {}
|
||||
for (let msg of parsed) {
|
||||
try {
|
||||
instances[msg[instanceField]].push(msg)
|
||||
} catch (e) {
|
||||
instances[msg[instanceField]] = [ msg ]
|
||||
}
|
||||
}
|
||||
if (Object.keys(instances).length === 1) {
|
||||
this.fixDataOnce(name)
|
||||
this.simplifyData(name)
|
||||
this.postData({messageType: name, messageList: this.messages[name]})
|
||||
return parsed
|
||||
}
|
||||
for (let [index, messages] of Object.entries(instances)) {
|
||||
let newName = name + '[' + index + ']'
|
||||
this.messages[newName] = messages
|
||||
this.fixDataOnce(newName)
|
||||
this.simplifyData(newName)
|
||||
this.postData({messageType: newName,
|
||||
messageList: this.messages[newName]})
|
||||
}
|
||||
} else if (parsed.length) {
|
||||
this.fixDataOnce(name)
|
||||
this.simplifyData(name)
|
||||
this.postData({messageType: name, messageList: this.messages[name]})
|
||||
}
|
||||
this.alreadyParsed.push(name)
|
||||
return parsed
|
||||
}
|
||||
|
||||
checkNumberOfInstances (name) {
|
||||
// Similar to parseOffset, but finishes earlier and updates messageTypes
|
||||
let type = this.getMsgType(name)
|
||||
let availableInstances = []
|
||||
let instanceField = this.getInstancesFieldName(name)
|
||||
if (instanceField === null) {
|
||||
return [1]
|
||||
}
|
||||
let repeats = 0
|
||||
for (var i = 0; i < this.msgType.length; i++) {
|
||||
if (type === this.msgType[i]) {
|
||||
this.offset = this.offsetArray[i]
|
||||
try {
|
||||
let temp = this.FORMAT_TO_STRUCT(this.FMT[this.msgType[i]])
|
||||
if (temp['name'] != null) {
|
||||
let msg = temp
|
||||
if (!msg.hasOwnProperty(instanceField)) {
|
||||
break
|
||||
}
|
||||
// we do an early return after we get 20 repeated instance numbers. should we?
|
||||
const instance = msg[instanceField]
|
||||
if (availableInstances.includes(instance)) {
|
||||
repeats += 1
|
||||
if (repeats > 20) {
|
||||
return availableInstances
|
||||
}
|
||||
} else {
|
||||
availableInstances.push(instance)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableInstances
|
||||
}
|
||||
|
||||
timestamp (TimeUs) {
|
||||
let temp = this.timebase + TimeUs * 0.000001
|
||||
if (temp > 0) {
|
||||
TimeUs = temp
|
||||
}
|
||||
let date = new Date(TimeUs * 1000)
|
||||
let hours = date.getHours()
|
||||
let minutes = '0' + date.getMinutes()
|
||||
let seconds = '0' + date.getSeconds()
|
||||
let formattedTime = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2)
|
||||
date = date.toString()
|
||||
let time = date.split(' ')
|
||||
if (time[0] !== 'Invalid') {
|
||||
this.time = time[0] + ' ' + time[1] + ' ' + time[2] + ' ' + time[3]
|
||||
}
|
||||
return formattedTime
|
||||
}
|
||||
|
||||
DfReader () {
|
||||
let lastOffset = 0
|
||||
while (this.offset < (this.buffer.byteLength - 3)) {
|
||||
if (this.data.getUint8(this.offset) !== HEAD1 || this.data.getUint8(this.offset + 1) !== HEAD2) {
|
||||
this.offset += 1
|
||||
continue
|
||||
}
|
||||
this.offset += 2
|
||||
|
||||
let attribute = this.data.getUint8(this.offset)
|
||||
if (this.FMT[attribute] != null) {
|
||||
this.offset += 1
|
||||
this.offsetArray.push(this.offset)
|
||||
this.msgType.push(attribute)
|
||||
try {
|
||||
var value = this.FORMAT_TO_STRUCT(this.FMT[attribute])
|
||||
if (this.FMT[attribute].Name === 'GPS') {
|
||||
this.findTimeBase(value)
|
||||
}
|
||||
} catch (e) {
|
||||
// console.log('reached log end?')
|
||||
// console.log(e)
|
||||
this.offset += 1
|
||||
}
|
||||
if (attribute === 128) {
|
||||
this.FMT[value['Type']] = {
|
||||
'Type': value['Type'],
|
||||
'length': value['Length'],
|
||||
'Name': value['Name'],
|
||||
'Format': value['Format'],
|
||||
'Columns': value['Columns']
|
||||
}
|
||||
}
|
||||
// this.onMessage(value)
|
||||
} else {
|
||||
this.offset += 1
|
||||
}
|
||||
if (this.offset - lastOffset > 50000) {
|
||||
let perc = 100 * this.offset / this.buffer.byteLength
|
||||
self.postMessage({percentage: perc})
|
||||
lastOffset = this.offset
|
||||
}
|
||||
}
|
||||
self.postMessage({percentage: 100})
|
||||
self.postMessage({messages: this.messages})
|
||||
this.sent = true
|
||||
}
|
||||
|
||||
getModeString (cmode) {
|
||||
let mavtype
|
||||
let msgs = this.messages['MSG']
|
||||
for (let i in msgs.Message) {
|
||||
if (msgs.Message[i].toLowerCase().includes('arduplane')) {
|
||||
mavtype = MAV_TYPE_FIXED_WING
|
||||
return getModeMap(mavtype)[cmode]
|
||||
} else if (msgs.Message[i].toLowerCase().includes('arducopter')) {
|
||||
mavtype = MAV_TYPE_QUADROTOR
|
||||
return getModeMap(mavtype)[cmode]
|
||||
} else if (msgs.Message[i].toLowerCase().includes('ardusub')) {
|
||||
mavtype = MAV_TYPE_SUBMARINE
|
||||
return getModeMap(mavtype)[cmode]
|
||||
} else if (msgs.Message[i].toLowerCase().includes('rover')) {
|
||||
mavtype = MAV_TYPE_GROUND_ROVER
|
||||
return getModeMap(mavtype)[cmode]
|
||||
} else if (msgs.Message[i].toLowerCase().includes('tracker')) {
|
||||
mavtype = MAV_TYPE_ANTENNA_TRACKER
|
||||
return getModeMap(mavtype)[cmode]
|
||||
}
|
||||
}
|
||||
console.log('defaulting to quadcopter')
|
||||
return getModeMap(MAV_TYPE_QUADROTOR)[cmode]
|
||||
}
|
||||
|
||||
fixData (message) {
|
||||
if (message.name === 'MODE') {
|
||||
message.asText = this.getModeString(message['Mode'])
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
message.time_boot_ms = message.TimeUS / 1000
|
||||
delete message.TimeUS
|
||||
delete message.fieldnames
|
||||
return message
|
||||
}
|
||||
|
||||
fixDataOnce (name) {
|
||||
if (!['GPS', 'ATT', 'AHR2', 'MODE'].includes(name)) {
|
||||
if (this.messageTypes.hasOwnProperty(name)) {
|
||||
let fields = this.messages[name][0].fieldnames
|
||||
if (this.messageTypes[name].hasOwnProperty('multipliers')) {
|
||||
for (let message in this.messages[name]) {
|
||||
for (let i = 1; i < fields.length; i++) {
|
||||
let fieldname = fields[i]
|
||||
if (!isNaN(this.messageTypes[name].multipliers[i])) {
|
||||
this.messages[name][message][fieldname] *= this.messageTypes[name].multipliers[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
concatTypedArrays (a, b) { // a, b TypedArray of same type
|
||||
var c = new (a.constructor)(a.length + b.length)
|
||||
c.set(a, 0)
|
||||
c.set(b, a.length)
|
||||
return c
|
||||
}
|
||||
|
||||
createUint8ArrayFromString (str) {
|
||||
const array = new Uint8Array(str.length)
|
||||
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
||||
array[i] = str.charCodeAt(i)
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
processFiles () {
|
||||
this.files = {}
|
||||
for (let msg of this.messages['FILE']) {
|
||||
if (!this.files.hasOwnProperty(msg.FileName)) {
|
||||
this.files[msg.FileName] = this.createUint8ArrayFromString(msg.Data)
|
||||
} else {
|
||||
this.files[msg.FileName] = this.concatTypedArrays(
|
||||
this.files[msg.FileName], this.createUint8ArrayFromString(msg.Data)
|
||||
)
|
||||
}
|
||||
}
|
||||
self.postMessage({files: this.files})
|
||||
}
|
||||
|
||||
simplifyData (name) {
|
||||
if (name === 'MODE') {
|
||||
this.messageTypes[name].expressions.push('asText')
|
||||
}
|
||||
if (name === 'FILE') {
|
||||
return
|
||||
}
|
||||
if (!['FMTU'].includes(name)) {
|
||||
if (this.messageTypes.hasOwnProperty(name)) {
|
||||
let fields = this.messageTypes[name].expressions
|
||||
if (!fields.includes('time_boot_ms')) {
|
||||
fields.push('time_boot_ms')
|
||||
}
|
||||
let mergedData = {}
|
||||
for (let field of fields) {
|
||||
mergedData[field] = []
|
||||
}
|
||||
for (let message of this.messages[name]) {
|
||||
for (let i = 1; i < fields.length; i++) {
|
||||
let fieldname = fields[i]
|
||||
mergedData[fieldname].push(message[fieldname])
|
||||
}
|
||||
}
|
||||
delete this.messages[name]
|
||||
this.messages[name] = mergedData
|
||||
for (const field of this.messageTypes[name].expressions) {
|
||||
if (this.messages[name][field] && !isNaN(this.messages[name][field][0])) {
|
||||
const newData = new Float64Array(this.messages[name][field])
|
||||
delete this.messages[name][field]
|
||||
this.messages[name][field] = newData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
populateUnits () {
|
||||
// console.log(this.messages['FMTU'])
|
||||
for (let msg of this.messages['FMTU']) {
|
||||
this.FMT[msg.FmtType]['units'] = []
|
||||
for (let unit of msg.UnitIds) {
|
||||
this.FMT[msg.FmtType]['units'].push(units[unit])
|
||||
}
|
||||
this.FMT[msg.FmtType]['multipliers'] = []
|
||||
for (let mult of msg.MultIds) {
|
||||
this.FMT[msg.FmtType]['multipliers'].push(multipliers[mult])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extractStartTime () {
|
||||
let msgs = this.messages['GPS']
|
||||
for (let i in msgs.time_boot_ms) {
|
||||
if (msgs.GWk[i] > 1000) { // lousy validation
|
||||
let weeks = msgs.GWk[i]
|
||||
let ms = msgs.GMS[i]
|
||||
let d = new Date((315964800.0 + ((60 * 60 * 24 * 7) * weeks) + ms / 1000.0) * 1000.0)
|
||||
// adjusting for leap seconds
|
||||
d = new Date(d.getTime() - this.leapSecondsGPS(d.getUTCFullYear(), d.getUTCMonth() + 1) * 1000)
|
||||
return d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leapSecondsGPS (year, month) {
|
||||
return this.leapSecondsTAI(year, month) - 19
|
||||
}
|
||||
|
||||
leapSecondsTAI (year, month) {
|
||||
const yyyymm = year * 100 + month
|
||||
if (yyyymm >= 201701) return 37
|
||||
if (yyyymm >= 201507) return 36
|
||||
if (yyyymm >= 201207) return 35
|
||||
if (yyyymm >= 200901) return 34
|
||||
if (yyyymm >= 200601) return 33
|
||||
if (yyyymm >= 199901) return 32
|
||||
if (yyyymm >= 199707) return 31
|
||||
if (yyyymm >= 199601) return 30
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
processData (data) {
|
||||
this.buffer = data
|
||||
this.data = new DataView(this.buffer)
|
||||
this.DfReader()
|
||||
let messageTypes = {}
|
||||
this.parseAtOffset('FMTU')
|
||||
this.populateUnits()
|
||||
let typeSet = new Set(this.msgType)
|
||||
for (let msg of this.FMT) {
|
||||
if (msg) {
|
||||
if (typeSet.has(msg.Type)) {
|
||||
let fields = msg.Columns.split(',')
|
||||
// expressions = expressions.filter(e => e !== 'TimeUS')
|
||||
let complexFields = {}
|
||||
if (msg.hasOwnProperty('units')) {
|
||||
for (let field in fields) {
|
||||
complexFields[fields[field]] = {
|
||||
name: fields[field],
|
||||
units: (multipliersTable[msg.multipliers[field]] || '') + msg.units[field],
|
||||
multiplier: msg.multipliers[field]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let field in fields) {
|
||||
complexFields[fields[field]] = {
|
||||
name: fields[field],
|
||||
units: '?',
|
||||
multiplier: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
let availableInstances = this.checkNumberOfInstances(msg.Name)
|
||||
if (availableInstances.length > 1) {
|
||||
for (let instance of availableInstances) {
|
||||
messageTypes[msg.Name + '[' + instance + ']'] = {
|
||||
expressions: fields,
|
||||
units: msg.units,
|
||||
multipiers: msg.multipliers,
|
||||
complexFields: complexFields
|
||||
}
|
||||
}
|
||||
} else {
|
||||
messageTypes[msg.Name] = {
|
||||
expressions: fields,
|
||||
units: msg.units,
|
||||
multipiers: msg.multipliers,
|
||||
complexFields: complexFields
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.postMessage({availableMessages: messageTypes})
|
||||
this.messageTypes = messageTypes
|
||||
this.parseAtOffset('CMD')
|
||||
this.parseAtOffset('MSG')
|
||||
this.parseAtOffset('FILE')
|
||||
this.processFiles()
|
||||
this.parseAtOffset('MODE')
|
||||
this.parseAtOffset('AHR2')
|
||||
this.parseAtOffset('ATT')
|
||||
this.parseAtOffset('GPS')
|
||||
this.parseAtOffset('POS')
|
||||
this.parseAtOffset('XKQ1')
|
||||
this.parseAtOffset('XKQ')
|
||||
this.parseAtOffset('NKQ1')
|
||||
this.parseAtOffset('NKQ2')
|
||||
this.parseAtOffset('XKQ2')
|
||||
this.parseAtOffset('PARM')
|
||||
this.parseAtOffset('MSG')
|
||||
this.parseAtOffset('STAT')
|
||||
this.parseAtOffset('EV')
|
||||
let metadata = {
|
||||
startTime: this.extractStartTime()
|
||||
}
|
||||
self.postMessage({metadata: metadata})
|
||||
|
||||
self.postMessage({messagesDoneLoading: true})
|
||||
return {types: this.messageTypes, messages: this.messages}
|
||||
}
|
||||
|
||||
loadType (type) {
|
||||
this.parseAtOffset(type)
|
||||
console.log('done')
|
||||
}
|
||||
}
|
||||
|
||||
self.addEventListener('message', function (event) {
|
||||
if (event.data === null) {
|
||||
console.log('got bad file message!')
|
||||
} else if (event.data.action === 'parse') {
|
||||
parser = new DataflashParser()
|
||||
let data = event.data.file
|
||||
parser.processData(data)
|
||||
} else if (event.data.action === 'loadType') {
|
||||
parser.loadType(event.data.type.split('[')[0])
|
||||
} else if (event.data.action === 'trimFile') {
|
||||
parser.trimFile(event.data.time)
|
||||
}
|
||||
})
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* FileSaver.js
|
||||
* A saveAs() FileSaver implementation.
|
||||
*
|
||||
* By Eli Grey, http://eligrey.com
|
||||
*
|
||||
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
|
||||
* source : http://purl.eligrey.com/github/FileSaver.js
|
||||
*/
|
||||
|
||||
// The one and only way of getting global scope in all environments
|
||||
// https://stackoverflow.com/q/3277182/1008999
|
||||
var _global = typeof window === 'object' && window.window === window
|
||||
? window : typeof self === 'object' && self.self === self
|
||||
? self : typeof global === 'object' && global.global === global
|
||||
? global
|
||||
: this
|
||||
|
||||
function bom (blob, opts) {
|
||||
if (typeof opts === 'undefined') opts = { autoBom: false }
|
||||
else if (typeof opts !== 'object') {
|
||||
console.warn('Deprecated: Expected third argument to be a object')
|
||||
opts = { autoBom: !opts }
|
||||
}
|
||||
|
||||
// prepend BOM for UTF-8 XML and text/* types (including HTML)
|
||||
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
||||
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||
return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
|
||||
}
|
||||
return blob
|
||||
}
|
||||
|
||||
function download (url, name, opts) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', url)
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = function () {
|
||||
saveAs(xhr.response, name, opts)
|
||||
}
|
||||
xhr.onerror = function () {
|
||||
console.error('could not download file')
|
||||
}
|
||||
xhr.send()
|
||||
}
|
||||
|
||||
function corsEnabled (url) {
|
||||
var xhr = new XMLHttpRequest()
|
||||
// use sync to avoid popup blocker
|
||||
xhr.open('HEAD', url, false)
|
||||
try {
|
||||
xhr.send()
|
||||
} catch (e) {}
|
||||
return xhr.status >= 200 && xhr.status <= 299
|
||||
}
|
||||
|
||||
// `a.click()` doesn't work for all browsers (#465)
|
||||
function click (node) {
|
||||
try {
|
||||
node.dispatchEvent(new MouseEvent('click'))
|
||||
} catch (e) {
|
||||
var evt = document.createEvent('MouseEvents')
|
||||
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
|
||||
20, false, false, false, false, 0, null)
|
||||
node.dispatchEvent(evt)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect WebView inside a native macOS app by ruling out all browsers
|
||||
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
|
||||
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
|
||||
var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
|
||||
|
||||
var saveAs = _global.saveAs || (
|
||||
// probably in some web worker
|
||||
(typeof window !== 'object' || window !== _global)
|
||||
? function saveAs () { /* noop */ }
|
||||
|
||||
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
|
||||
: ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
|
||||
? function saveAs (blob, name, opts) {
|
||||
var URL = _global.URL || _global.webkitURL
|
||||
var a = document.createElement('a')
|
||||
name = name || blob.name || 'download'
|
||||
|
||||
a.download = name
|
||||
a.rel = 'noopener' // tabnabbing
|
||||
|
||||
// TODO: detect chrome extensions & packaged apps
|
||||
// a.target = '_blank'
|
||||
|
||||
if (typeof blob === 'string') {
|
||||
// Support regular links
|
||||
a.href = blob
|
||||
if (a.origin !== location.origin) {
|
||||
corsEnabled(a.href)
|
||||
? download(blob, name, opts)
|
||||
: click(a, a.target = '_blank')
|
||||
} else {
|
||||
click(a)
|
||||
}
|
||||
} else {
|
||||
// Support blobs
|
||||
a.href = URL.createObjectURL(blob)
|
||||
setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
|
||||
setTimeout(function () { click(a) }, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Use msSaveOrOpenBlob as a second approach
|
||||
: 'msSaveOrOpenBlob' in navigator
|
||||
? function saveAs (blob, name, opts) {
|
||||
name = name || blob.name || 'download'
|
||||
|
||||
if (typeof blob === 'string') {
|
||||
if (corsEnabled(blob)) {
|
||||
download(blob, name, opts)
|
||||
} else {
|
||||
var a = document.createElement('a')
|
||||
a.href = blob
|
||||
a.target = '_blank'
|
||||
setTimeout(function () { click(a) })
|
||||
}
|
||||
} else {
|
||||
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to using FileReader and a popup
|
||||
: function saveAs (blob, name, opts, popup) {
|
||||
// Open a popup immediately do go around popup blocker
|
||||
// Mostly only available on user interaction and the fileReader is async so...
|
||||
popup = popup || open('', '_blank')
|
||||
if (popup) {
|
||||
popup.document.title =
|
||||
popup.document.body.innerText = 'downloading...'
|
||||
}
|
||||
|
||||
if (typeof blob === 'string') return download(blob, name, opts)
|
||||
|
||||
var force = blob.type === 'application/octet-stream'
|
||||
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
|
||||
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
|
||||
|
||||
if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
|
||||
// Safari doesn't allow downloading of blob URLs
|
||||
var reader = new FileReader()
|
||||
reader.onloadend = function () {
|
||||
var url = reader.result
|
||||
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
|
||||
if (popup) popup.location.href = url
|
||||
else location = url
|
||||
popup = null // reverse-tabnabbing #460
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
} else {
|
||||
var URL = _global.URL || _global.webkitURL
|
||||
var url = URL.createObjectURL(blob)
|
||||
if (popup) popup.location = url
|
||||
else location.href = url
|
||||
popup = null // reverse-tabnabbing #460
|
||||
setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
_global.saveAs = saveAs.saveAs = saveAs
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = saveAs;
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import os
|
||||
from flask import Flask
|
||||
from flask import render_template
|
||||
|
||||
# A flask app to allow hosting filter tool locally
|
||||
|
||||
this_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
app = Flask(__name__, template_folder=this_path, static_folder=this_path)
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run()
|
File diff suppressed because it is too large
Load Diff
@ -1,378 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>ArduPilot Filter Analysis</title>
|
||||
<script type="text/javascript" src="filters.js"></script>
|
||||
<script type="text/javascript" src="FileSaver.js"></script>
|
||||
<script type="text/javascript" src={{url_for('static', filename='filters.js')}}></script>
|
||||
<script type="text/javascript" src={{url_for('static', filename='FileSaver.js')}}></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
|
||||
<script src="https://www.lactame.com/lib/ml/6.0.0/ml.min.js"></script>
|
||||
</head>
|
||||
<a href="https://ardupilot.org"><img src="logo.png"></a>
|
||||
<h1>ArduPilot Filter Analysis</h1>
|
||||
|
||||
The following form will display the attenuation and phase lag for an
|
||||
ArduPilot 4.2 filter setup.
|
||||
<body onload="load(); fill_docs(); update_all_hidden(); check_nyquist(); calculate_filter(); calculate_pid();">
|
||||
<canvas id="Attenuation" style="width:100%;max-width:1200px"></canvas>
|
||||
<canvas id="Phase" style="width:100%;max-width:1200px;"></canvas>
|
||||
<p>
|
||||
<input type="button" id="calculate" value="Calculate">
|
||||
<input type="button" id="SaveParams" value="Save Parameters" onclick="save_parameters();">
|
||||
<button class="styleClass" onclick="document.getElementById('param_file').click()">Load Parameters</button>
|
||||
<input type='file' id="param_file" style="display:none" onchange="load_parameters(this.files[0]);">
|
||||
<input type="button" id="GetLink" value="Get Link" onclick="get_link();">
|
||||
|
||||
<form id="params" action="">
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Graph Settings</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Magnitude scale</legend>
|
||||
<input type="radio" id="ScaleLog" name="Scale" value="Log" checked>
|
||||
<label for="LogScale">dB</label><br>
|
||||
<input type="radio" id="ScaleLinear" name="Scale" value="Linear">
|
||||
<label for="LinearScale">Linear</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Phase scale</legend>
|
||||
<input type="radio" id="ScaleUnWrap" name="PhaseScale" value="unwrap" checked>
|
||||
<label for="ScaleUnWrap">un-wrapped</label><br>
|
||||
<input type="radio" id="ScaleWrap" name="PhaseScale" value="wrap">
|
||||
<label for="ScaleWrap">±180</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Frequency scale</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" id="freq_ScaleLog" name="feq_scale" value="Log" checked>
|
||||
<label for="LogScale">Log</label><br>
|
||||
<input type="radio" id="freq_ScaleLinear" name="feq_scale" value="Linear">
|
||||
<label for="LinearScale">Linear</label><br>
|
||||
</td>
|
||||
<td>
|
||||
<input type="radio" id="freq_Scale_Hz" name="feq_unit" value="Hz" checked>
|
||||
<label for="Scale_unit_Hz">Hz</label><br>
|
||||
<input type="radio" id="freq_Scale_RPM" name="feq_unit" value="RPM">
|
||||
<label for="Scale_unit_RPM">RPM</label><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>
|
||||
<label for="MaxFreq">Maximum Displayed Frequency</label>
|
||||
<input id="MaxFreq" name="MaxFreq" type="number" step="1" value="150" onchange="check_nyquist();"/>
|
||||
<label id="MaxFreq_warning"></label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="MaxPhaseLag">Maximum Displayed Phase Lag</label>
|
||||
<input id="MaxPhaseLag" name="MaxPhaseLag" type="number" step="1" value="360"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>INS Settings</legend>
|
||||
<p>
|
||||
<label for="GyroSampleRate">Gyro Sample Rate</label>
|
||||
<input id="GyroSampleRate" name="GYRO_SAMPLE_RATE" type="number" step="1" value="2000" onchange="check_nyquist();"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_GYRO_FILTER">INS_GYRO_FILTER</label>
|
||||
<input id="INS_GYRO_FILTER" name="INS_GYRO_FILTER" type="number" step="0.1" value="20.0"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>First Notch Filter</legend>
|
||||
<p>
|
||||
<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="update_hidden(this.id); fill_docs();"/>
|
||||
<label id="INS_HNTCH_ENABLE.doc"></label>
|
||||
</p>
|
||||
<p>
|
||||
<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="update_hidden_mode(); fill_docs();"/>
|
||||
<label id="INS_HNTCH_MODE.doc"></label>
|
||||
</p>
|
||||
<p>
|
||||
<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"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTCH_BW">INS_HNTCH_BW</label>
|
||||
<input id="INS_HNTCH_BW" name="INS_HNTCH_BW" type="number" step="0.1" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTCH_ATT">INS_HNTCH_ATT</label>
|
||||
<input id="INS_HNTCH_ATT" name="INS_HNTCH_ATT" type="number" step="0.1" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<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"/>
|
||||
</p>
|
||||
<p>
|
||||
<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"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTCH_HMNCS">INS_HNTCH_HMNCS</label>
|
||||
<input id="INS_HNTCH_HMNCS" name="INS_HNTCH_HMNCS" type="number" step="1" value="1"/>
|
||||
<label id="INS_HNTCH_HMNCS.doc"></label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTCH_OPTS">INS_HNTCH_OPTS</label>
|
||||
<input id="INS_HNTCH_OPTS" name="INS_HNTCH_OPTS" type="number" step="1" value="0"/>
|
||||
<label id="INS_HNTCH_OPTS.doc"></label>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Second Notch Filter</legend>
|
||||
<p>
|
||||
<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="update_hidden(this.id); fill_docs();"/>
|
||||
<label id="INS_HNTC2_ENABLE.doc"></label>
|
||||
</p>
|
||||
<p>
|
||||
<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="update_hidden_mode(); fill_docs();"/>
|
||||
<label id="INS_HNTC2_MODE.doc"></label>
|
||||
</p>
|
||||
<p>
|
||||
<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"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTC2_BW">INS_HNTC2_BW</label>
|
||||
<input id="INS_HNTC2_BW" name="INS_HNTC2_BW" type="number" step="0.1" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTC2_ATT">INS_HNTC2_ATT</label>
|
||||
<input id="INS_HNTC2_ATT" name="INS_HNTC2_ATT" type="number" step="0.1" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<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"/>
|
||||
</p>
|
||||
<p>
|
||||
<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"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTC2_HMNCS">INS_HNTC2_HMNCS</label>
|
||||
<input id="INS_HNTC2_HMNCS" name="INS_HNTC2_HMNCS" type="number" step="1" value="1"/>
|
||||
<label id="INS_HNTC2_HMNCS.doc"></label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="INS_HNTC2_OPTS">INS_HNTC2_OPTS</label>
|
||||
<input id="INS_HNTC2_OPTS" name="INS_HNTC2_OPTS" type="number" step="1" value="0"/>
|
||||
<label id="INS_HNTC2_OPTS.doc"></label>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px" id="Throttle_input">
|
||||
<legend>Throttle Based</legend>
|
||||
<p>
|
||||
<label for="Throttle">Throttle</label>
|
||||
<input id="Throttle" name="Throttle" type="number" step="0.01" value="0.3"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px" id="ESC_input">
|
||||
<legend>ESC Telemetry</legend>
|
||||
<p>
|
||||
<label for="NUM_MOTORS">Number of Motors</label>
|
||||
<input id="NUM_MOTORS" name="NUM_MOTORS" type="number" step="1" value="1"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ESC_RPM">ESC RPM</label>
|
||||
<input id="ESC_RPM" name="ESC_RPM" type="number" step="1" value="2500"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px" id="RPM_input">
|
||||
<legend>RPM/EFI Based</legend>
|
||||
<p>
|
||||
<label for="RPM1">RPM1</label>
|
||||
<input id="RPM1" name="RPM1" type="number" step="1" value="2500"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="RPM2">RPM2</label>
|
||||
<input id="RPM2" name="RPM2" type="number" step="1" value="2500"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<h2>PIDs</h2>
|
||||
<h3><label id="PID_title">Title</label></h3>
|
||||
<canvas id="PID_Attenuation" style="width:100%;max-width:1200px"></canvas>
|
||||
<canvas id="PID_Phase" style="width:100%;max-width:1200px"></canvas>
|
||||
<p>
|
||||
<input type="button" id="CalculateRoll" value="Caculate Roll" onclick="calculate_pid(this.id);">
|
||||
<input type="button" id="CalculatePitch" value="Caculate Pitch" onclick="calculate_pid(this.id);">
|
||||
<input type="button" id="CalculateYaw" value="Caculate Yaw" onclick="calculate_pid(this.id);">
|
||||
</p>
|
||||
<form id="PID_params" action="">
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Graph Settings</legend>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Gain scale</legend>
|
||||
<input type="radio" id="PID_ScaleLog" name="PID_Scale" value="Log" checked>
|
||||
<label for="LogScale">dB</label><br>
|
||||
<input type="radio" id="PID_ScaleLinear" name="PID_Scale" value="Linear">
|
||||
<label for="LinearScale">Linear</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Phase scale</legend>
|
||||
<input type="radio" id="PID_ScaleUnWrap" name="PID_PhaseScale" value="unwrap" checked>
|
||||
<label for="ScaleUnWrap">un-wrapped</label><br>
|
||||
<input type="radio" id="PID_ScaleWrap" name="PID_PhaseScale" value="wrap">
|
||||
<label for="ScaleWrap">±180</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Frequency scale</legend>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="radio" id="PID_freq_ScaleLog" name="PID_feq_scale" value="Log" checked>
|
||||
<label for="LogScale">Log</label><br>
|
||||
<input type="radio" id="PID_freq_ScaleLinear" name="PID_feq_scale" value="Linear">
|
||||
<label for="LinearScale">Linear</label><br>
|
||||
</td>
|
||||
<td>
|
||||
<input type="radio" id="PID_freq_Scale_Hz" name="PID_feq_unit" value="Hz" checked>
|
||||
<label for="Scale_unit_Hz">Hz</label><br>
|
||||
<input type="radio" id="PID_freq_Scale_RPM" name="PID_feq_unit" value="RPM">
|
||||
<label for="Scale_unit_RPM">RPM</label><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
</td>
|
||||
<td>
|
||||
<fieldset style="width:150px">
|
||||
<legend>Filtering</legend>
|
||||
<input type="radio" id="PID_filtering_Pre" name="filtering" value="Pre" checked>
|
||||
<label for="LogScale">Pre</label><br>
|
||||
<input type="radio" id="PID_filtering_Post" name="filtering" value="Post">
|
||||
<label for="LinearScale">Post</label><br>
|
||||
</fieldset>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<p>
|
||||
<label for="PID_MaxFreq">Maximum Displayed Frequency</label>
|
||||
<input id="PID_MaxFreq" name="PID_MaxFreq" type="number" step="1" value="150" onchange="check_nyquist();"/>
|
||||
<label id="PID_MaxFreq_warning"></label>
|
||||
</p>
|
||||
<p>
|
||||
<label for="PID_MaxPhaseLag">Maximum Displayed Phase Lag</label>
|
||||
<input id="PID_MaxPhaseLag" name="PID_MaxPhaseLag" type="number" step="1" value="360"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Loop Rate</legend>
|
||||
<p>
|
||||
<label for="SCHED_LOOP_RATE">SCHED_LOOP_RATE</label>
|
||||
<input id="SCHED_LOOP_RATE" name="SCHED_LOOP_RATE" type="number" step="1" value="400" onchange="check_nyquist();"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Roll</legend>
|
||||
<p>
|
||||
<label for="ATC_RAT_RLL_P">ATC_RAT_RLL_P</label>
|
||||
<input id="ATC_RAT_RLL_P" name="ATC_RAT_RLL_P" type="number" step="0.01" value="0.135"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_RLL_I">ATC_RAT_RLL_I</label>
|
||||
<input id="ATC_RAT_RLL_I" name="ATC_RAT_RLL_I" type="number" step="0.01" value="0.135"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_RLL_D">ATC_RAT_RLL_D</label>
|
||||
<input id="ATC_RAT_RLL_D" name="ATC_RAT_RLL_D" type="number" step="0.0001" value="0.0036"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_RLL_FLTE">ATC_RAT_RLL_FLTE</label>
|
||||
<input id="ATC_RAT_RLL_FLTE" name="ATC_RAT_RLL_FLTE" type="number" step="0.01" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_RLL_FLTD">ATC_RAT_RLL_FLTD</label>
|
||||
<input id="ATC_RAT_RLL_FLTD" name="ATC_RAT_RLL_FLTD" type="number" step="0.01" value="20"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Pitch</legend>
|
||||
<p>
|
||||
<label for="ATC_RAT_PIT_P">ATC_RAT_PIT_P</label>
|
||||
<input id="ATC_RAT_PIT_P" name="ATC_RAT_PIT_P" type="number" step="0.01" value="0.135"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_PIT_I">ATC_RAT_PIT_I</label>
|
||||
<input id="ATC_RAT_PIT_I" name="ATC_RAT_PIT_I" type="number" step="0.01" value="0.135"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_PIT_D">ATC_RAT_PIT_D</label>
|
||||
<input id="ATC_RAT_PIT_D" name="ATC_RAT_PIT_D" type="number" step="0.0001" value="0.0036"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_PIT_FLTE">ATC_RAT_PIT_FLTE</label>
|
||||
<input id="ATC_RAT_PIT_FLTE" name="ATC_RAT_PIT_FLTE" type="number" step="0.01" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_PIT_FLTD">ATC_RAT_PIT_FLTD</label>
|
||||
<input id="ATC_RAT_PIT_FLTD" name="ATC_RAT_PIT_FLTD" type="number" step="0.01" value="20"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
<fieldset style="max-width:1200px">
|
||||
<legend>Yaw</legend>
|
||||
<p>
|
||||
<label for="ATC_RAT_YAW_P">ATC_RAT_YAW_P</label>
|
||||
<input id="ATC_RAT_YAW_P" name="ATC_RAT_YAW_P" type="number" step="0.01" value="0.09"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_YAW_I">ATC_RAT_YAW_I</label>
|
||||
<input id="ATC_RAT_YAW_I" name="ATC_RAT_YAW_I" type="number" step="0.01" value="0.009"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_YAW_D">ATC_RAT_YAW_D</label>
|
||||
<input id="ATC_RAT_YAW_D" name="ATC_RAT_YAW_D" type="number" step="0.0001" value="0"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_YAW_FLTE">ATC_RAT_YAW_FLTE</label>
|
||||
<input id="ATC_RAT_YAW_FLTE" name="ATC_RAT_YAW_FLTE" type="number" step="0.01" value="2.5"/>
|
||||
</p>
|
||||
<p>
|
||||
<label for="ATC_RAT_YAW_FLTD">ATC_RAT_YAW_FLTD</label>
|
||||
<input id="ATC_RAT_YAW_FLTD" name="ATC_RAT_YAW_FLTD" type="number" step="0.01" value="0"/>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
var calc_btn = document.getElementById('calculate');
|
||||
calc_btn.onclick = function() {
|
||||
calculate_filter();
|
||||
}
|
||||
//var clear_btn = document.getElementById('clear_cookies');
|
||||
//clear_btn.onclick = function() {
|
||||
// clear_cookies();
|
||||
//}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user