# Visualize Custom Flight Log

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 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 $\mathit{m}/{\mathit{s}}^{2}$. The next 3 columns are gyroscope readings in $\mathrm{rad}/\mathit{s}$, and the last 3 columns are magnetometer readings in $\mu 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 $\mathit{m}$. The next 3 columns are velocity in XYZ NED direction in $\mathit{m}/\mathit{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 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 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 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 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```