Main Content

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 m/s2. The next 3 columns are gyroscope readings in rad/s, and the last 3 columns are magnetometer readings in μT.

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 m. The next 3 columns are velocity in XYZ NED direction in m/s, 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