added geoplot function

This commit is contained in:
v.chau 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 !!!
See Example: start the App in Matlab the correct folder (see picture), otherwise it will throw an error
![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)
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)
KNOWN ERRORS / NOT WORKING / UNKNOWN
- FT25-Presets -> instead use Load(fast) and Plot Subplot
- new implementation of date selection might mess with lap selection
- unknown status of Presets for FT23 and FT24 after the last few updates, might not work
- should the imported data contain more than one day, preconfigured presets will might not work
- geoplot was not tested throughly, might not work with subplotting, so close the figures before you plot either of them
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
- you need to delete your search if you misspelled something
- 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>)
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:
1. Browse the .mat file you want to open. (put it into /data folder)
2. Choose either Load (fast) or Load (Presets)
- Load(fast):
- will load ONLY the name of all saved data in your .mat file
- 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)
4 seperate datasets:
app.data - main dataset for custom plots
app.data_created - dataset created by custom functions/filter, can be appended to app.data via synchronize()
app.data_tr = app.data(tr,:) - main dataset cut down with timestamp (timerange tr)
app.pltData - main dataset for preset dataset

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