Configure the flightLogSignalMapping
object to visualize data from a 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 could properly handle the log data saved in the mat file and visualize them. The data, customFlightData.mat
, stores a struct 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 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: [2785x9 double]
Fs: 100
Trajectory: [2785x10 double]
The IMU
field in logData
is an n-by-9 matrix, with the first 3 columns as 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
A flightLogSignalMapping
object is created with no input argument since the custom log format is 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 has a "#" symbol suffix. This means that you can optionally suffix these signal names with integers so that the flight log plotter can handle multiple of signals of this kind, such as secondary IMU signals, barometer readings, etc. 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 signalsfor 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 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);
For mod details 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 argument. 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.
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