Visualize Custom Flight Log
Configure the flightLogSignalMapping
object to visualize data from a custom flight log.
Load Custom Flight Log
In this example, it is assumed that flight data is already parsed into MATLAB® and stored as a MAT file. This example focuses on configuring the flightLogSignalMapping
object so that it can properly handle the log data saved in the MAT file and visualize it. The data, customFlightData.mat
, stores a structure that contains 3 fields. Fs
is the sampling frequency of the signals stored in the MAT file. IMU
and Trajectory
are matrices containing actual flight information. The trajectory data and IMU data are based on a simulated flight that follows a projected rectangular path on an xy-plane.
customData = load("customFlightData.mat");
logData = customData.logData
logData = struct with fields:
IMU: [2785×9 double]
Fs: 100
Trajectory: [2785×10 double]
The IMU
field in logData
is an n-by-9 matrix, where the first 3 columns are accelerometer readings in . The next 3 columns are gyroscope readings in , and the last 3 columns are magnetometer readings in .
logData.IMU(1:5, :)
ans = 5×9
0.8208 0.7968 10.7424 0.0862 0.0873 0.0862 327.6000 297.6000 283.8000
0.8016 0.8160 10.7904 0.0883 0.0873 0.0862 327.6000 297.6000 283.8000
0.7680 0.7680 10.7568 0.0862 0.0851 0.0851 327.6000 297.6000 283.8000
0.8208 0.7536 10.7520 0.0873 0.0883 0.0819 327.6000 297.6000 283.8000
0.7872 0.7728 10.7328 0.0873 0.0862 0.0830 327.6000 297.6000 283.8000
The Trajectory
field in logData
is an n-by-9 matrix, with the first 3 columns are XYZ NED coordinates in . The next 3 columns are velocity in XYZ NED direction in , and the last 4 columns are quaternions describing the UAV rotation from the inertia NED frame to body frame. Each row is a single point of the trajectory with all these parameters defined.
logData.Trajectory(1:5,:)
ans = 5×10
0.0200 0 -4.0000 2.0000 0 -0.0036 1.0000 0 0 -0.0000
0.0400 0 -4.0001 2.0000 0 -0.0072 1.0000 0 0 -0.0000
0.0600 0 -4.0002 2.0000 0 -0.0108 1.0000 0 0 -0.0000
0.0800 0 -4.0003 2.0000 0 -0.0143 1.0000 0 0 -0.0000
0.1000 0 -4.0004 2.0000 0 -0.0179 1.0000 0 0 -0.0001
Visualize Custom Flight Log Using Predefined Signal Format and Plots
Create a flightLogSignalMapping
object with no input argument since the custom log format does not following a standard "ulog"
or "tlog"
definition.
customPlotter = flightLogSignalMapping;
The object has a predefined set of signals that you can map. By mapping these predefined signals, you gain access to a set of predefined plots. Notice that a few signals have a "#" symbol suffix. For these signals, you can optionally add integers as suffixes to the signal names so that the flight log plotter can handle multiple of signals of this kind, such as secondary IMU signals and barometer readings. Call info
.
% Predefined signals info(customPlotter, "Signal")
ans=18×4 table
SignalName IsMapped SignalFields FieldUnits
_____________________ ________ __________________________________________________________________________________________________________________________________________________________________________________________________________ ___________________________________________________
"Accel#" false "AccelX, AccelY, AccelZ" "m/s^2, m/s^2, m/s^2"
"Airspeed#" false "PressDiff, IndicatedAirSpeed, Temperature" "Pa, m/s, degreeC"
"AttitudeEuler" false "Roll, Pitch, Yaw" "rad, rad, rad"
"AttitudeRate" false "BodyRotationRateX, BodyRotationRateY, BodyRotationRateZ" "rad/s, rad/s, rad/s"
"AttitudeTargetEuler" false "RollTarget, PitchTarget, YawTarget" "rad, rad, rad"
"Barometer#" false "PressAbs, PressAltitude, Temperature" "Pa, m, degreeC"
"Battery" false "Voltage_1, Voltage_2, Voltage_3, Voltage_4, Voltage_5, Voltage_6, Voltage_7, Voltage_8, Voltage_9, Voltage_10, Voltage_11, Voltage_12, Voltage_13, Voltage_14, Voltage_15, Voltage_16, RemainingCapacity" "v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, %"
"GPS#" false "Latitude, Longitude, Altitude, GroundSpeed, CourseAngle, SatellitesVisible" "degree, degree, m, m/s, degree, N/A"
"Gyro#" false "GyroX, GyroY, GyroZ" "rad/s, rad/s, rad/s"
"LocalENU" false "X, Y, Z" "m, m, m"
"LocalENUTarget" false "XTarget, YTarget, ZTarget" "m, m, m"
"LocalENUVel" false "VX, VY, VZ" "m/s, m/s, m/s"
"LocalENUVelTarget" false "VXTarget, VYTarget, VZTarget" "m/s, m/s, m/s"
"LocalNED" false "X, Y, Z" "m, m, m"
"LocalNEDTarget" false "XTarget, YTarget, ZTarget" "m, m, m"
"LocalNEDVel" false "VX, VY, VZ" "m/s, m/s, m/s"
⋮
% Predefined plots info(customPlotter,"Plot")
ans=10×4 table
PlotName ReadyToPlot MissingSignals RequiredSignals
_______________________ ___________ ____________________________________ ____________________________________
"Attitude" false "AttitudeEuler, AttitudeRate, Gyro#" "AttitudeEuler, AttitudeRate, Gyro#"
"AttitudeControl" false "AttitudeEuler, AttitudeTargetEuler" "AttitudeEuler, AttitudeTargetEuler"
"Battery" false "Battery" "Battery"
"Compass" false "AttitudeEuler, Mag#, GPS#" "AttitudeEuler, Mag#, GPS#"
"GPS2D" false "GPS#" "GPS#"
"Height" false "Barometer#, GPS#, LocalNED" "Barometer#, GPS#, LocalNED"
"Speed" false "GPS#, Airspeed#" "GPS#, Airspeed#"
"Trajectory" false "LocalNED, LocalNEDTarget" "LocalNED, LocalNEDTarget"
"TrajectoryTracking" false "LocalNED, LocalNEDTarget" "LocalNED, LocalNEDTarget"
"TrajectoryVelTracking" false "LocalNEDVel, LocalNEDVelTarget" "LocalNEDVel, LocalNEDVelTarget"
The flightLogSignalMapping
object needs to know how data is stored in the flight log before it can visualize the data. To associate signal names with function handles that access the relevant information in the logData
, you must map signals using mapSignal
. Each signal is defined as a timestamp vector and a signal value matrix.
For example, to map the Gyro#
signal, define a timeAccess
function handle based on the sensor data sampling frequency. This function handle generates the timestamp vector for the signal values using a global timestamp interval for the data.
timeAccess = @(x)seconds(1/x.Fs*(1:size(x.IMU)));
Next, check what fields must be defined for the Gyro#
signal using info
.
info(customPlotter,"Signal","Gyro#")
ans=1×4 table
SignalName IsMapped SignalFields FieldUnits
__________ ________ _____________________ _____________________
"Gyro#" false "GyroX, GyroY, GyroZ" "rad/s, rad/s, rad/s"
The Gyro#
signal needs three columns containing the gyroscope readings for the XYZ axes. Define the gyroAccess
function handle accordingly and map it with timeAccess
using mapSignal
.
gyroAccess = @(x)x.IMU(:,4:6);
mapSignal(customPlotter,"Gyro",timeAccess,gyroAccess);
Similarly, map other predefined signals for data that is present in the flight log. Define the value function handles for the data. Map the signals using the same timeAccess
timestamp vector function.
% IMU data stores accelerometer and magnetometer data. accelAccess = @(x)x.IMU(:,1:3); magAccess = @(x)x.IMU(:,7:9)*1e-2; % Flight trajectory in local NED coordinates % XYZ coordinates nedAccess = @(x)x.Trajectory(:, 1:3); % XYZ celocities nedVelAccess = @(x)x.Trajectory(:, 4:6); % Roll Pitch Yaw rotations converted from a quaternion attitudeAccess = @(x)flip(quat2eul(x.Trajectory(:, 7:10)),2); % Configure flightLogSignalMapping for custom data mapSignal(customPlotter, "Accel", timeAccess, accelAccess); mapSignal(customPlotter, "Mag", timeAccess, magAccess); mapSignal(customPlotter, "LocalNED", timeAccess, nedAccess); mapSignal(customPlotter, "LocalNEDVel", timeAccess, nedVelAccess); mapSignal(customPlotter, "AttitudeEuler", timeAccess, attitudeAccess);
Once all signals are mapped, customPlotter
is ready to generate plots based on signal data stored in the log. To quickly check if the signals are correctly mapped call checkSignal and specify the logData.
checkSignal(customPlotter,logData);
-------------------------------------------- SignalName: Gyro Pass -------------------------------------------- SignalName: Accel Pass -------------------------------------------- SignalName: Mag Pass -------------------------------------------- SignalName: LocalNED Pass -------------------------------------------- SignalName: LocalNEDVel Pass -------------------------------------------- SignalName: AttitudeEuler Pass
To get a preview of a mapped signal select the preview option in checkSignal.
checkSignal(customPlotter,logData,'Preview',"on",'Signal',"Accel");
-------------------------------------------- SignalName: Accel Pass Press a key to continue or 'q' to quit. Figure needs to be in focus.
To visualize the flight log data, call show
and specify logData
. All the plots available based on the mapped signals are shown in figures.
predefinedPlots = show(customPlotter,logData);
Visualize Custom Flight Log with Custom Plot
For more detailed log analysis, define more signals and add more plots other than predefined plots stored in flightLogSignalMapping
. Specify a function handle that filters accelerations greater than 1.
accelThreshold = @(x)(vecnorm(accelAccess(x)')>11)'; mapSignal(customPlotter, "HighAccel", timeAccess,accelThreshold, "AccelGreaterThan11", "N/A");
Call updatePlot
to add custom plots. Specify the flight log plotter object and a name for the plot as the first two arguments. To specify a time series of data, use "Timeseries"
as the third argument, and then list the data.
updatePlot(customPlotter, "AnalyzeAccel","Timeseries",["HighAccel.AccelGreaterThan11", "LocalNEDVel.VX", "LocalNEDVel.VY", "LocalNEDVel.VZ"]);
Define a custom function handle for generating a figure handle (see function definition below). This function generates a periodogram using fft
and other functions on the acceleration data and plots them. The function returns a function handle.
updatePlot(customPlotter, "plotFFTAccel",@(acc)plotFFTAccel(acc),"Accel");
Check that customPlotter
now contains a new signal and two new plots using info
.
info(customPlotter, "Signal")
ans=19×4 table
SignalName IsMapped SignalFields FieldUnits
_____________________ ________ __________________________________________________________________________________________________________________________________________________________________________________________________________ ___________________________________________________
"Accel" true "AccelX, AccelY, AccelZ" "m/s^2, m/s^2, m/s^2"
"AttitudeEuler" true "Roll, Pitch, Yaw" "rad, rad, rad"
"Gyro" true "GyroX, GyroY, GyroZ" "rad/s, rad/s, rad/s"
"HighAccel" true "AccelGreaterThan11" "N/A"
"LocalNED" true "X, Y, Z" "m, m, m"
"LocalNEDVel" true "VX, VY, VZ" "m/s, m/s, m/s"
"Mag" true "MagX, MagY, MagZ" "Gs, Gs, Gs"
"Airspeed#" false "PressDiff, IndicatedAirSpeed, Temperature" "Pa, m/s, degreeC"
"AttitudeRate" false "BodyRotationRateX, BodyRotationRateY, BodyRotationRateZ" "rad/s, rad/s, rad/s"
"AttitudeTargetEuler" false "RollTarget, PitchTarget, YawTarget" "rad, rad, rad"
"Barometer#" false "PressAbs, PressAltitude, Temperature" "Pa, m, degreeC"
"Battery" false "Voltage_1, Voltage_2, Voltage_3, Voltage_4, Voltage_5, Voltage_6, Voltage_7, Voltage_8, Voltage_9, Voltage_10, Voltage_11, Voltage_12, Voltage_13, Voltage_14, Voltage_15, Voltage_16, RemainingCapacity" "v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, v, %"
"GPS#" false "Latitude, Longitude, Altitude, GroundSpeed, CourseAngle, SatellitesVisible" "degree, degree, m, m/s, degree, N/A"
"LocalENU" false "X, Y, Z" "m, m, m"
"LocalENUTarget" false "XTarget, YTarget, ZTarget" "m, m, m"
"LocalENUVel" false "VX, VY, VZ" "m/s, m/s, m/s"
⋮
info(customPlotter, "Plot")
ans=12×4 table
PlotName ReadyToPlot MissingSignals RequiredSignals
_______________________ ___________ _____________________ ____________________________________
"AnalyzeAccel" true "" "HighAccel, LocalNEDVel"
"Attitude" true "AttitudeRate" "AttitudeEuler, AttitudeRate, Gyro#"
"AttitudeControl" true "AttitudeTargetEuler" "AttitudeEuler, AttitudeTargetEuler"
"Compass" true "GPS#" "AttitudeEuler, Mag#, GPS#"
"Height" true "Barometer#, GPS#" "Barometer#, GPS#, LocalNED"
"Trajectory" true "LocalNEDTarget" "LocalNED, LocalNEDTarget"
"TrajectoryTracking" true "LocalNEDTarget" "LocalNED, LocalNEDTarget"
"TrajectoryVelTracking" true "LocalNEDVelTarget" "LocalNEDVel, LocalNEDVelTarget"
"plotFFTAccel" true "" "Accel"
"Battery" false "Battery" "Battery"
"GPS2D" false "GPS#" "GPS#"
"Speed" false "GPS#, Airspeed#" "GPS#, Airspeed#"
Specify which plot names you want to plot. Call show
using "PlotsToShow"
to visualize the analysis of the acceleration data.
accelAnalysisProfile = ["AnalyzeAccel", "plotFFTAccel"]; accelAnalysisPlots = show(customPlotter, logData, "PlotsToShow", accelAnalysisProfile);
This example has shown how to use the flightLogSignalMapping
object to look at predefined signals and plots, as well as customize your own plots for flight log analysis.
Analyze Acceleration Data Function Definition
function h = plotFFTAccel(acc) h = figure("Name", "AccelFFT"); ax = newplot(h); v = acc.Values{1}; Fs = v.Properties.SampleRate; N = floor(length(v.AccelX)/2)*2; hold(ax, "on"); for idx = 1:3 x = v{1:N, idx}; xdft = fft(x); xdft = xdft(1:N/2+1); psdx = (1/(Fs*N)) * abs(xdft).^2; psdx(2:end-1) = 2*psdx(2:end-1); freq = 0:Fs/length(x):Fs/2; plot(ax, freq, 10*log10(psdx)); end hold(ax, "off"); title("Periodogram Using FFT"); xlabel("f (Hz)"); ylabel("Power/Frequency (dB/Hz)"); legend("AccelX", "AccelY", "AccelZ"); end