added geoplot function

This commit is contained in:
2025-08-29 18:48:09 +02:00
parent 4bcd68f244
commit 69e506d815
6 changed files with 86 additions and 108 deletions

View File

@ -1,68 +1,42 @@
!!! Important !!! !!! Important !!!
See Example: start the App in Matlab the correct folder (see picture), otherwise it will throw an error See Example: start the App in Matlab the correct folder (see picture), otherwise it will give out an error
![double click app.mlapp in this folder! make sure ](tutorial/image.png)! ![double click app.mlapp in this folder! make sure ](tutorial/image.png)
Updated app is out. Check out app2 (everything except laps, grayed out buttons and presets works, presets might work in old app)
KNOWN ERRORS / NOT WORKING / UNKNOWN KNOWN ERRORS / NOT WORKING / UNKNOWN
- FT25-Presets -> instead use Load(fast) and Plot Subplot - should the imported data contain more than one day, preconfigured presets will might not work
- new implementation of date selection might mess with lap selection - geoplot was not tested throughly, might not work with subplotting, so close the figures before you plot either of them
- unknown status of Presets for FT23 and FT24 after the last few updates, might not work
FYI: FYI:
- code is starting to get really clunky, going to rewrite the handling of loaded data some time in the future
- search is case sensitive - search is case sensitive
- you need to delete your search if you misspelled something - you need to delete your search if you misspelled something
- if something doesnt work try reset subplot and then press plot subplot again - if something doesnt work try reset subplot and then press plot subplot again
Short tutorial:
Part 1 - General Tab:
![Tutorial for new app2](<tutorial/app2 tutorial.png>) ![Tutorial for new app2](<tutorial/app2 tutorial.png>)
Part 2 - Preset Tab:
![Tutorial for new app2 - presets](<tutorial/app2 tutorial - presets.png>)
Part 3 - Geoplot:
- need to manually load latitude and longitude
- third value can be inserted as linecolor by choosing a dataset in the dropdown next to custom geoplot
- can also apply timestamps like the subplots
![Tutorial for new app2 - Geoplot](<tutorial/geoplot.png>)
Quick notes:
There are two options to plot data
- 1. Tab: General
- Allows to make custom plots based on the data you have choosen
- Allows to apply external functions saved in the folder "functions" to be applied to loaded dataset
- Note: check "example.m" in the functions folder to learn how to make a custom function (there are some rules)
- Timestamped data can only be created from app.data / Loaded Datasets
- To timestamp the data you created with custom functions you need to append it first
- 2. Tab: Presets
- this tab allows you to plot and save preconfigured seasonal presets
- presets exist for the seasons 23,24,25
- check the Dropdown Box to see which plots are available
Quick tutorial: 4 seperate datasets:
1. Browse the .mat file you want to open. (put it into /data folder) app.data - main dataset for custom plots
2. Choose either Load (fast) or Load (Presets) app.data_created - dataset created by custom functions/filter, can be appended to app.data via synchronize()
- Load(fast): app.data_tr = app.data(tr,:) - main dataset cut down with timestamp (timerange tr)
- will load ONLY the name of all saved data in your .mat file app.pltData - main dataset for preset dataset
- select data you want to plot in custom subplots -> select data (left side)
- all features will work for this option
- for customizing look under the next chapter
- Load (Presets)
- will load a pre configured set of data in your .mat file (takes a bit of time)
- choose a preset and a season, then press "Plot Presets"
-> will plot pre configured graphs
- all features in "Custom Subplots" do NOT work with this
- the idea is that only sortdata.m and the plot_settings need to be configured each season
- for customizing look under the next chapter (only features within Set Timestamps panel work)
Features:
1. Set Timestamps:
- works for both
- entire stint (all data recorded) is the default option that will be plotted
- otherwise you can select either the detected laps (will plot, but laps might be inaccurately recorded) or custom timestamps (remember to tick the Use box)
2. Reset Panel and To Workspace Buttons:
- work only for Presets
- should something not work try pressing reset and plot preset again
- to workspace throws the entire preset dataset into the matlab workspace (for further manipulation)
- currently limited in capabilites
3. Custom Subplots:
- only works for the selected data (if you press load preset you can also use the displayed data, but somethings like cell voltages might not be avaible)
- columns and rows to set the number of plots you want in one figure
- press Plot Subplot to plot
- how it works:
![selected subplot is 1](tutorial/1.png)
![this time a lap, and a different dataset was selected](tutorial/2.png)
![only if you want a second -yaxis select the option "plot with 2nd yAxis](tutorial/3.png)
- press reset subplot to delete the selected graph
Presets:
Adapting a preset:
- sortdata creates an struct pltData with all necessary data for plot_settings
- easiest case: the data from the vectorlogger has the same fieldnames as last season -> probably no changes necessary, unless you want to plot different things
- vectorlogger fieldnames changed: adapt the fieldname to the updated name
- otherwise: add missing data with pltData.XXX =
- plot_settings: uses the data given from pltData to plot, adapt as you see fit
- plotData currently hands over all data that use the following strings:
- "ABX*","Shunt*","AMS_Status*","INV*","XSens*
- which can make problems (e.g. FT23 and FT25 use XSens, FT24 uses VN200)

Binary file not shown.

BIN
legacy/app.mlapp Normal file

Binary file not shown.

View File

@ -1,44 +1,45 @@
function [pltData] = sortdata(data,start,stop) function [pltData, stats] = sortdata(data)
date = dateshift(data.Time(1),'start','day'); date = dateshift(data.Time(1),'start','day');
time_hms = data.Time-date; time_hms = data.Time-date;
time_s = seconds(time_hms); time_s = seconds(time_hms);
time_s = time_s - time_s(1); % set beginning of session to 0 time_s = time_s - time_s(1); % set beginning of session to 0
% x-Axis: % x-Axis:
pltData.Time = data.Time(start:stop); pltData.time_s = time_s;
pltData.time_s = time_s(start:stop)-time_s(start); pltData.time_hms = time_hms;
pltData.time_hms = time_hms(start:stop);
% distance calculation % distance calculation
speed_mps = movmean(data.ABX_Driver_ABX_Speed(start:stop),50); % TODO: test different speed filters for distance calculation speed_mps = movmean(data.FTCU_Driver_FTCU_Speed,50); % TODO: test different speed filters for distance calculation
pltData.distance(1) = 0; pltData.distance(1) = 0;
for i = 2:length(speed_mps) for i = 2:length(speed_mps)
pltData.distance(i) = speed_mps(i)*(pltData.time_s(i)-pltData.time_s(i-1)) + pltData.distance(i-1); pltData.distance(i) = speed_mps(i)*(time_s(i)-time_s(i-1)) + pltData.distance(i-1);
end end
pltData.distance = pltData.distance.';
pltData.xAxis = pltData.time_s; % set time as default x-Axis for plotting pltData.xAxis = pltData.time_s; % set time as default x-Axis for plotting
%% Misc %% Misc
pltData.app_percent = data.ABX_Driver_ABX_APPS_percent(start:stop); pltData.app_percent = data.FTCU_Driver_FTCU_APPS_Percent;
pltData.speed_kph = 3.6*movmean(data.ABX_Driver_ABX_Speed(start:stop),50); % same filter as for distance calculation ??? pltData.speed_kph = 3.6*movmean(data.FTCU_Driver_FTCU_Speed,50); % same filter as for distance calculation ???
pltData.steering_deg = data.ABX_Driver_ABX_Steering_Angle(start:stop); pltData.steering_deg = data.FTCU_Driver_FTCU_Steering_Angle;
%% AMS: %% AMS:
pltData.ams_soc = data.AMS_Status_SOC(start:stop); pltData.ams_soc = data.AMS_Status_SOC;
pltData.ams_tmax = data.AMS_Status_Max_cell_temp(start:stop); pltData.ams_tmax = data.AMS_Status_Max_cell_temp;
pltData.ams_utot = data.Shunt_Voltage1_Shunt_Voltage1(start:stop); pltData.ams_utot = data.Shunt_Voltage1_Shunt_Voltage1;
pltData.ams_itot = data.Shunt_Current_Shunt_Current(start:stop); pltData.ams_itot = data.Shunt_Current_Shunt_Current;
% calculations: % calculations:
pltData.ams_ptot = pltData.ams_utot.*pltData.ams_itot/1000; pltData.ams_ptot = pltData.ams_utot.*pltData.ams_itot/1000;
%% Brakes %% Brakes
% brake pressure % brake pressure
pltData.brakePFront_bar = data.ABX_Driver_ABX_BrakeP_F(start:stop); pltData.brakePFront_bar = data.FTCU_Driver_FTCU_Brake_Pressure_F;
pltData.brakePRear_bar = data.ABX_Driver_ABX_BrakeP_R(start:stop); pltData.brakePRear_bar = data.FTCU_Driver_FTCU_Brake_Pressure_R;
% brake disc temperatures % brake disc temperatures
pltData.brakeTFrontLeft_degC = data.ABX_BrakeT_ABX_BrakeT_FL(start:stop); pltData.brakeTFrontLeft_degC = data.Sensornode_F_10Hz_BDTS_FL;
pltData.brakeTFrontRight_degC = data.ABX_BrakeT_ABX_BrakeT_FR(start:stop); pltData.brakeTFrontRight_degC = data.Sensornode_F_10Hz_BDTS_FR;
pltData.brakeTRearLeft_degC = data.ABX_BrakeT_ABX_BrakeT_RL(start:stop); pltData.brakeTRearLeft_degC = data.Sensornode_R_10Hz_BDTS_RL;
pltData.brakeTRearRight_degC = data.ABX_BrakeT_ABX_BrakeT_RR(start:stop); pltData.brakeTRearRight_degC = data.Sensornode_R_10Hz_BDTS_RR;
% calculate brake bias [%] % calculate brake bias [%]
minBrakeP = 5; % minimum brake pressure to avoid artifacts due to sensor noise near 0 bar minBrakeP = 5; % minimum brake pressure to avoid artifacts due to sensor noise near 0 bar
brakePFront = pltData.brakePFront_bar; brakePFront = pltData.brakePFront_bar;
@ -51,10 +52,10 @@ function [pltData] = sortdata(data,start,stop)
%% Dampers %% Dampers
% damper positions % damper positions
pltData.damper_FL_mm = data.ABX_Dampers_ABX_Damper_FL(start:stop); %Heave_F pltData.damper_FL_mm = data.Sensornode_F_100Hz_2_DS_FL; %Heave_F
pltData.damper_FR_mm = data.ABX_Dampers_ABX_Damper_FR(start:stop); %Roll_F pltData.damper_FR_mm = data.Sensornode_F_100Hz_2_DS_FR; %Roll_F
pltData.damper_RL_mm = data.ABX_Dampers_ABX_Damper_RL(start:stop); %Heave_R pltData.damper_RL_mm = data.Sensornode_R_100Hz_DS_RL; %Heave_R
pltData.damper_RR_mm = data.ABX_Dampers_ABX_Damper_RR(start:stop); %Roll_R pltData.damper_RR_mm = data.Sensornode_R_100Hz_DS_RR; %Roll_R
% calculate damper velocities % calculate damper velocities
pltData.velocity_FL_mmps(1) = 0; pltData.velocity_FL_mmps(1) = 0;
pltData.velocity_FR_mmps(1) = 0; pltData.velocity_FR_mmps(1) = 0;
@ -68,36 +69,36 @@ function [pltData] = sortdata(data,start,stop)
pltData.velocity_RR_mmps(i) = pltData.damper_RR_mm(i)-pltData.damper_RR_mm(i-1)/timestep; pltData.velocity_RR_mmps(i) = pltData.damper_RR_mm(i)-pltData.damper_RR_mm(i-1)/timestep;
end end
% filter damper velocities ??? bessere Berechnung über mittelwert aus mehreren werten? Vorfilterung? % filter damper velocities ??? bessere Berechnung über mittelwert aus mehreren werten? Vorfilterung?
pltData.velocity_FL_mmps = movmean(pltData.velocity_FL_mmps,100); pltData.velocity_FL_mmps = movmean(pltData.velocity_FL_mmps,100).';
pltData.velocity_FR_mmps = movmean(pltData.velocity_FR_mmps,100); pltData.velocity_FR_mmps = movmean(pltData.velocity_FR_mmps,100).';
pltData.velocity_RL_mmps = movmean(pltData.velocity_RL_mmps,100); pltData.velocity_RL_mmps = movmean(pltData.velocity_RL_mmps,100).';
pltData.velocity_RR_mmps = movmean(pltData.velocity_RR_mmps,100); pltData.velocity_RR_mmps = movmean(pltData.velocity_RR_mmps,100).';
%% IMU %% IMU - VN200, no need to implement didnt work well anyway
% Acceleration % Acceleration
pltData.acc_long_g = movmean(data.XSens_Acceleration_XSens_accX(start:stop),100)/9.81; pltData.acc_long_g = movmean(data.XSens_Acceleration_XSens_accX,100)/9.81;
pltData.acc_lat_g = movmean(data.XSens_Acceleration_XSens_accY(start:stop),100)/9.81; pltData.acc_lat_g = movmean(data.XSens_Acceleration_XSens_accY,100)/9.81;
% Rate of turn % Rate of turn
pltData.rot_roll_degps = movmean(data.XSens_RateOfTurn_XSens_gyrX(start:stop),100); pltData.rot_roll_degps = movmean(data.XSens_rateofturn_XSens_gyrX,100);
pltData.rot_pitch_degps = movmean(data.XSens_RateOfTurn_XSens_gyrY(start:stop),100); pltData.rot_pitch_degps = movmean(data.XSens_rateofturn_XSens_gyrY,100);
pltData.rot_yaw_degps = movmean(data.XSens_RateOfTurn_XSens_gyrZ(start:stop),100); pltData.rot_yaw_degps = movmean(data.XSens_rateofturn_XSens_gyrZ,100);
%% Inverters %% Inverters
% inverter temperatures % inverter temperatures
pltData.invL_temp = data.INV_L_TxPDO_1_T_Inv_L(start:stop); pltData.invL_temp = data.INV_1_TxPDO_1_T_Inv_1; % not sure if 1 is left and 2 is right
pltData.invR_temp = data.INV_R_TxPDO_1_T_Inv_R(start:stop); pltData.invR_temp = data.INV_2_TxPDO_1_T_Inv_2;
% motor temperatures % motor temperatures
pltData.motL_temp = data.INV_L_TxPDO_1_T_Mot_L(start:stop); pltData.motL_temp = data.INV_1_TxPDO_1_T_Mot_1; % not sure if 1 is left and 2 is right
pltData.motR_temp = data.INV_R_TxPDO_1_T_Mot_R(start:stop); pltData.motR_temp = data.INV_2_TxPDO_1_T_Mot_2;
% motor velocities % motor velocities
pltData.motL_vel_rpm = 60*data.INV_L_TxPDO_4_Velocity_L(start:stop); pltData.motL_vel_rpm = 60*data.INV_1_TxPDO_4_Velocity_1; % not sure if 1 is left and 2 is right
pltData.motR_vel_rpm = 60*data.INV_R_TxPDO_4_Velocity_R(start:stop); pltData.motR_vel_rpm = 60*data.INV_2_TxPDO_4_Velocity_2;
% inverter torque demand % inverter torque demand
pltData.invL_torqueDemand = data.INV_L_TxPDO_3_DemandedTorque_L(start:stop)/10; % /10 to match autobox torque pltData.invL_torqueDemand = data.INV_1_TxPDO_3_DemandedTorque_1/10; % /10 to match autobox torque % not sure if 1 is left and 2 is right
pltData.invR_torqueDemand = data.INV_R_TxPDO_3_DemandedTorque_R(start:stop)/10; pltData.invR_torqueDemand = data.INV_2_TxPDO_3_DemandedTorque_2/10;
% inverter actual torque % inverter actual torque
pltData.invL_torqueActual = data.INV_L_TxPDO_3_ActualTorque_L(start:stop)/10; pltData.invL_torqueActual = data.INV_1_TxPDO_3_DemandedTorque_1/10; % not sure if 1 is left and 2 is right
pltData.invR_torqueActual = data.INV_R_TxPDO_3_ActualTorque_R(start:stop)/10; pltData.invR_torqueActual = data.INV_2_TxPDO_3_DemandedTorque_2/10;
%% Wheelspeed %% Wheelspeed
@ -109,15 +110,18 @@ function [pltData] = sortdata(data,start,stop)
power_regen_kw(power_regen_kw > 0) = 0; power_regen_kw(power_regen_kw > 0) = 0;
power_used_kw = pltData.ams_ptot; power_used_kw = pltData.ams_ptot;
power_used_kw(power_used_kw < 0) = 0; power_used_kw(power_used_kw < 0) = 0;
pltData.energy_kwh = trapz(pltData.time_s, pltData.ams_ptot)/3600; stats.energy_kwh = trapz(time_s, pltData.ams_ptot)/3600;
pltData.energy_regen_kwh = trapz(pltData.time_s, power_regen_kw)/3600; stats.energy_regen_kwh = trapz(time_s, power_regen_kw)/3600;
pltData.energy_used_kwh = trapz(pltData.time_s, power_used_kw)/3600; stats.energy_used_kwh = trapz(time_s, power_used_kw)/3600;
pltData.distanceTotal_km = trapz(pltData.time_s, pltData.speed_kph./3.6)/1000; % 1/3.6 for km/h to m/s and /1000 for km output stats.distanceTotal_km = trapz(time_s, pltData.speed_kph./3.6)/1000; % 1/3.6 for km/h to m/s and /1000 for km output
pltData.peakPower_kw = max(pltData.ams_ptot); stats.peakPower_kw = max(pltData.ams_ptot);
pltData.peakPowerMean_kw = max(movmean(pltData.ams_ptot,500)); stats.peakPowerMean_kw = max(movmean(pltData.ams_ptot,500));
pltData.maxSpeed_kph = max(pltData.speed_kph); stats.maxSpeed_kph = max(pltData.speed_kph);
pltData.startTime = time_hms(start); % pltData.startTime = time_hms(1);
pltData.stopTime = time_hms(stop); % pltData.stopTime = time_hms(end);
%% struct2timetable
pltData = table2timetable(struct2table(pltData), "RowTimes", data.Time);
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
tutorial/geoplot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB