This example shows how to visualize simulated versus actual flight trajectories with the animation object (Aero.Animation) while showing some of the animation object functionality. In this example, you can use the Aero.Animation object to create and configure an animation object, then use that object to create, visualize, and manipulate bodies for the flight trajectories.
This code creates an instance of the Aero.Animation
object.
h = Aero.Animation;
This code sets the number of frames per second. This controls the rate at which frames are displayed in the figure window.
h.FramesPerSecond = 10;
This code sets the seconds of animation data per second time scaling. This property and the 'FramesPerSecond'
property determine the time step of the simulation. The settings in this example result in a time step of approximately 0.5s. The equation is (1/FramesPerSecond)*TimeScaling along with some extra terms to handle for sub-second precision.
h.TimeScaling = 5;
This code loads the bodies using createBody
for the animation object, h
. This example will use these bodies to work with and display the simulated and actual flight trajectories. The first body is orange and will represent simulated data. The second body is blue and will represent the actual flight data.
idx1 = h.createBody('pa24-250_orange.ac','Ac3d'); idx2 = h.createBody('pa24-250_blue.ac','Ac3d');
Using the bodies from the previous code, this code provides simulated and actual recorded data for flight trajectories in the following files:
The simdata file contains logged simulated data. simdata
is set up as a 6DoF array, which is one of the default data formats.
The fltdata file contains actual flight test data. In this example, fltdata
is set up in a custom format. The example must create a custom read function and set the 'TimeSeriesSourceType'
parameter to 'Custom'
.
To load the simdata and fltdata files:
load simdata load fltdata
To work with the custom flight test data, this code sets the second body 'TimeSeriesReadFcn'
. The custom read function is located here: matlabroot/toolbox/aero/astdemos/CustomReadBodyTSData.m
h.Bodies{2}.TimeseriesReadFcn = @CustomReadBodyTSData;
Set the bodies' timeseries data.
h.Bodies{1}.TimeSeriesSource = simdata;
h.Bodies{2}.TimeSeriesSource = fltdata;
h.Bodies{2}.TimeSeriesSourceType = 'Custom';
This code illustrates how you can manipulate the camera for the two bodies.
The 'PositionFcn'
property of a camera object controls the camera position relative to the bodies in the animation. The default camera 'PositionFcn'
follows the path of a first order chase vehicle. Therefore, it takes a few steps for the camera to position itself correctly in the chase plane position. The default 'PositionFcn'
is located here: matlabroot/toolbox/aero/aero/doFirstOrderChaseCameraDynamics.m
Set 'PositionFcn'
.
h.Camera.PositionFcn = @doFirstOrderChaseCameraDynamics;
This code uses the show
method to create the figure graphics object for the animation object.
h.show();
This code uses the play
method to animate bodies for the duration of the timeseries data. Using this method will illustrate the slight differences between the simulated and flight data.
h.play();
The code can also use a custom, simplified 'PositionFcn'
that is a static position based on the position of the bodies (i.e., no dynamics). The simplified 'PositionFcn'
is located here: matlabroot/toolbox/aero/astdemos/staticCameraPosition.m
Set the new 'PositionFcn'
.
h.Camera.PositionFcn = @staticCameraPosition;
Run the animation with new 'PositionFcn'
.
h.play();
This code illustrates how to move the bodies to the starting position (based on timeseries data) and update the camera position according to the new 'PositionFcn'
. This code uses updateBodies
and updateCamera
.
t = 0; h.updateBodies(t); h.updateCamera(t);
This code illustrates how to reposition the bodies by first getting the current body position and then separating the bodies.
Get current body positions and rotations from the body objects.
pos1 = h.Bodies{1}.Position; rot1 = h.Bodies{1}.Rotation; pos2 = h.Bodies{2}.Position; rot2 = h.Bodies{2}.Rotation;
Separate bodies using moveBody
. This code separates and repositions the two bodies.
h.moveBody(1,pos1 + [0 0 -3],rot1); h.moveBody(2,pos1 + [0 0 0],rot2);
This code illustrates how to create transparency in the first body. The code does this by changing the body patch properties via 'PatchHandles'
. (For more information on patches in MATLAB®, see the Introduction to Patch Objects
section in the MATLAB documentation.)
Note: On some platforms utilizing software OpenGL® rendering, the transparency may cause a decrease in animation speed.
See the opengl
documentation for more information on OpenGL in MATLAB.
To create a transparency, the code gets the patch handles for the first body.
patchHandles2 = h.Bodies{1}.PatchHandles;
Set desired face and edge alpha values.
desiredFaceTransparency = .3; desiredEdgeTransparency = 1;
This code gets the current face and edge alpha data and changes all values to desired alpha values. In the figure, notice the first body now has a transparency.
for k = 1:size(patchHandles2,1) tempFaceAlpha = get(patchHandles2(k),'FaceVertexAlphaData'); tempEdgeAlpha = get(patchHandles2(k),'EdgeAlpha'); set(patchHandles2(k),... 'FaceVertexAlphaData',repmat(desiredFaceTransparency,size(tempFaceAlpha))); set(patchHandles2(k),... 'EdgeAlpha',repmat(desiredEdgeTransparency,size(tempEdgeAlpha))); end
This code illustrates how to change the body color of the second body. The code does this by changing the body patch properties via 'PatchHandles'
.
patchHandles3 = h.Bodies{2}.PatchHandles;
This code sets the desired patch color (red).
desiredColor = [1 0 0];
The code can now get the current face color data and change all values to desired color values. Note the following points on the code:
The if
condition keeps the windows from being colored.
The name property is stored in the geometry data of the body (h.Bodies{2}.Geometry.FaceVertexColorData(k).name).
The code only changes the indices in patchHandles3
with non-window counterparts in the body geometry data.
The name property might not always be available to determine various parts of the vehicle. In these cases, you will need to use an alternative approach to selective coloring.
for k = 1:size(patchHandles3,1) tempFaceColor = get(patchHandles3(k),'FaceVertexCData'); tempName = h.Bodies{2}.Geometry.FaceVertexColorData(k).name; if ~contains(tempName,'Windshield') &&... ~contains(tempName,'front-windows') &&... ~contains(tempName,'rear-windows') set(patchHandles3(k),... 'FaceVertexCData',repmat(desiredColor,[size(tempFaceColor,1),1])); end end
The following code turns off the landing gear for the second body. To do this, it turns off the visibility of all vehicle parts associated with the landing gear. Note the indices into the patchHandles3
vector were determined from the name property in the geometry data. Other data sources might not have this information available. In these cases, you will need to know which indices correspond to particular parts of the geometry.
for k = [1:8,11:14,52:57] set(patchHandles3(k),'Visible','off') end
To close and delete
h.delete();
%#ok<*REPMAT>