├── GPETT ├── compute_GP_covariance.m ├── demo.m ├── filter_GPETT3D.m ├── get_measurements.m ├── rotation_matrix_from_global_to_local.m └── visualize_tracking_outputs.m ├── GPETTP ├── compute_GP_covariance.m ├── demo.m ├── filter_GPETT3DProjection.m ├── get_measurements.m ├── reconstruct_from_projections.m ├── rotation_matrix_from_global_to_local.m └── visualize_tracking_outputs.m └── README.md /GPETT/compute_GP_covariance.m: -------------------------------------------------------------------------------- 1 | function [ covMatrix ] = compute_GP_covariance(argArray1, argArray2, paramGP) 2 | % This function computes the GP covariance according to the specified parameters. 3 | % Output: 4 | % covMatrix: The covariance matrix computed by the GP kernel. 5 | % Inputs: 6 | % argArray1: Each row is a pair of spherical angles, i.e., = [azimuth elevation] 7 | % argArray2: Each row is a pair of spherical angles, i.e., = [azimuth elevation] 8 | % paramGP: Parameters of the underlying GP 9 | 10 | % Extract parameters 11 | kernelType = paramGP{1}; 12 | stdPrior = paramGP{2}; 13 | stdRadius = paramGP{3}; 14 | scaleLength = paramGP{4}; 15 | isObjectSymmetric = paramGP{5}; 16 | 17 | switch kernelType 18 | 19 | case 1 20 | % Periodic squared exponential kernel 21 | diffMatrix = compute_diffence_matrix(argArray1, argArray2); 22 | 23 | if isObjectSymmetric 24 | % Periodic with pi (it imposes the symmetry of the object) 25 | covMatrix = stdPrior^2 * exp(-sin(diffMatrix).^2 / (2*scaleLength^2)) + stdRadius^2; 26 | else 27 | % Covariance periodic with 2pi 28 | covMatrix = stdPrior^2 * exp(-diffMatrix.^2 / (2*scaleLength^2)) + stdRadius^2; 29 | end 30 | 31 | case 2 32 | % Matern 3_2 kernel 33 | diffMatrix = compute_diffence_matrix(argArray1, argArray2); 34 | covMatrix = stdPrior^2 * (1+sqrt(3)/scaleLength*diffMatrix) .* exp(-sqrt(3)/scaleLength*diffMatrix); 35 | 36 | case 3 37 | % Matern 5_2 kernel 38 | diffMatrix = compute_diffence_matrix(argArray1, argArray2); 39 | covMatrix = stdPrior^2 * (1+sqrt(5)/scaleLength*diffMatrix... 40 | + 5/(3*scaleLength^2)*diffMatrix.^2) .* exp(-sqrt(5)/scaleLength*diffMatrix); 41 | end 42 | end 43 | 44 | 45 | function [ diffMatrix ] = compute_diffence_matrix( inp1, inp2 ) 46 | % This function calculates the difference matrix regarding two inputs. 47 | % inp1, inp2: Each row is of the form [azimuthAngle elevationAngle] 48 | 49 | % Produce a grid structure to be able to compute each angle between 50 | % elements of two inputs. 51 | len1 = size(inp1, 1); % The number of spherical angles, : [azi_1 elv_1;... azi_N elv_N] 52 | len2 = size(inp2, 1); % The number of spherical angles: : [azi_1 elv_1;... azi_N elv_N] 53 | 54 | % Extract azimuth and elevation angles from the inputs 55 | aziArray1 = inp1(:,1); 56 | elvArray1 = inp1(:,2); 57 | aziArray2 = inp2(:,1); 58 | eleArray2 = inp2(:,2); 59 | 60 | % Create matrices from these vectors to form grid structure 61 | aziGrid1 = repmat(aziArray1, [1, len2]); 62 | elvGrid1 = repmat(elvArray1, [1, len2]); 63 | aziGrid2 = repmat(transpose(aziArray2), [len1, 1]); 64 | elvGrid2 = repmat(transpose(eleArray2), [len1, 1]); 65 | 66 | % Put the matrices into vectors to feed to the angle computation procedure 67 | aziArray1 = aziGrid1(:); 68 | elvArray1 = elvGrid1(:); 69 | aziArray2 = aziGrid2(:); 70 | eleArray2 = elvGrid2(:); 71 | 72 | % Prepare the arrays for the following function 73 | sphrCoorArray1 = [aziArray1 elvArray1]; 74 | sphrCoorArray2 = [aziArray2 eleArray2]; 75 | 76 | % Calculate the the difference (spherical angle) 77 | diffArray = compute_angle_btw_sphr_coor(sphrCoorArray1, sphrCoorArray2); 78 | 79 | % Transform difference array back in matrix form 80 | diffMatrix = reshape(diffArray, len1, len2); 81 | end 82 | 83 | function [ angle ] = compute_angle_btw_sphr_coor( sphrCoor1, sphrCoor2 ) 84 | % The function computes the angle between two Spherical coordinates. 85 | % sphrCoor1, sphrCoor2 are in the form of : [azimuthAngle elevationAngle]. Note that 86 | % azimuthAngle and elevation angle can also be column vectors. 87 | 88 | azi1 = sphrCoor1(:, 1); 89 | elv1 = sphrCoor1(:, 2); 90 | azi2 = sphrCoor2(:, 1); 91 | elv2 = sphrCoor2(:, 2); 92 | 93 | % Calculate trigonometric multiplications 94 | multCosAzi = cos(azi1) .* cos(azi2); 95 | multSinAzi = sin(azi1) .* sin(azi2); 96 | multSinElv = sin(elv1) .* sin(elv2); 97 | multCosElv = cos(elv1) .* cos(elv2); 98 | 99 | angle = real(acos(multCosElv.*multCosAzi + multCosElv.*multSinAzi + multSinElv)); 100 | end 101 | -------------------------------------------------------------------------------- /GPETT/demo.m: -------------------------------------------------------------------------------- 1 | % This file presents a demonstration of the extended tracker proposed in 2 | % Section V of the following study. 3 | 4 | % For the details, please see: 5 | % M. Kumru and E. Özkan, “Three-Dimensional Extended Object Tracking 6 | % and Shape Learning Using Gaussian Processes”, 7 | % IEEE Transactions on Aerospace and Electronic Systems, 2021. 8 | % https://ieeexplore.ieee.org/abstract/document/9382878/ 9 | 10 | % Dependencies: 11 | % "Spheretri" package by Peter Gagarinov 12 | % It is utilized to produce uniformly distributed points on the unit sphere. 13 | % https://www.mathworks.com/matlabcentral/fileexchange/58453-spheretri 14 | 15 | clc; 16 | clear; 17 | close all; 18 | 19 | 20 | %% Paramaters 21 | % Simulation Parameters 22 | expDuration = 30; % (in seconds) 23 | T = 0.1; % sampling time (in seconds) 24 | eps = 1e-6; % a small scalar 25 | 26 | % Measurement Parameters 27 | numMeasPerInstant = 20; 28 | paramMeas = {numMeasPerInstant, expDuration, T}; 29 | 30 | % Gaussian Process (GP) Parameters 31 | minNumBasisAngles = 200; % minimum number of basis angles on which the extent is maintained 32 | meanGP = 0; % mean of the GP 33 | stdPriorGP = 1; % prior standard deviation of the GP 34 | stdRadiusGP = 0.2; % standard deviation of the radius 35 | scaleLengthGP = pi/8; % lengthscale 36 | kernelTypeGP = 1; % 1:Squared exponential , 2: Matern3_2, 3: Matern5_2 37 | isObjSymmetric = 0; % it is used to adjust the kernel function accordingly 38 | stdMeasGP = 0.1; % standard deviation of the measurements (used in the GP model) 39 | paramGP = {kernelTypeGP, stdPriorGP, stdRadiusGP, scaleLengthGP, isObjSymmetric, stdMeasGP, meanGP}; 40 | 41 | % EKF Paramaters 42 | stdCenter = 1e-1; % std dev of the process noise for object center 43 | stdAngVel = 1e-1; % std dev of the process noise for angular velocity 44 | lambda = 0.99; 45 | 46 | % Determine the Basis Angles 47 | [basisVertices, ~] = spheretri(minNumBasisAngles); % produces evenly spaced points on the sphere 48 | [azimuthBasisArray, elevationBasisArray, ~] = cart2sph(basisVertices(:,1), basisVertices(:,2)... 49 | , basisVertices(:,3)); 50 | azimuthBasisArray = mod(azimuthBasisArray, 2*pi); % to make it consistent with the convention 51 | numBasisAngles = size(basisVertices, 1); 52 | % Arrange the basis array so that azimuth and elevation are in ascending order 53 | basisAngleArray = [azimuthBasisArray elevationBasisArray]; 54 | basisAngleArray = sortrows(basisAngleArray, 2); 55 | basisAngleArray = sortrows(basisAngleArray, 1); 56 | 57 | 58 | %% Load Measurements and Ground Truth 59 | [measComplete, groundTruth] = get_measurements(paramMeas); 60 | 61 | 62 | %% Specify the Initial Distribution 63 | % Initial covariance 64 | P0_c = 0.1 * eye(3); 65 | P0_v = 0.1 * eye(3); 66 | P0_a = 1e-5 * eye(3,3); 67 | P0_w = 1e-0 * eye(3,3); 68 | P0_extent = compute_GP_covariance(basisAngleArray, basisAngleArray, paramGP); 69 | P0 = blkdiag(P0_c, P0_v, P0_a, P0_w, P0_extent); 70 | 71 | % Initial mean 72 | c0 = groundTruth.dataLog(1, 2:4)'+ sqrt(0.1)*randn(3,1); % initial linear velocity 73 | v0 = [0.5 0 0]'+ sqrt(0.1)*randn(3,1); % initial linear velocity 74 | q0 = [0 0 0 1]'; % initial quaternions 75 | a0 = [0 0 0]'; % initial orientation deviation 76 | w0 = [0 0 0]'; % initial angular velocity 77 | f0 = meanGP * ones(numBasisAngles, 1); % initial extent (is initialized regarding the GP model) 78 | 79 | % Initialize the filter estimate 80 | estState = [c0; v0; a0; w0; f0]; 81 | estQuat = q0; 82 | estStateCov = P0; 83 | 84 | 85 | %% Define the Process Model 86 | F_lin = kron([1 T; 0 1], eye(3)); % constant velocity model for linear motion 87 | F_rot = eye(6,6); % a substitute matrix for the rotational dynamics (it will be computed in the filter at each recursion) 88 | F_f = eye(numBasisAngles); 89 | F = blkdiag(F_lin, F_rot, F_f); 90 | 91 | Q_lin = kron([T^3/3 T^2/2; T^2/2 T], stdCenter^2*eye(3)); % process covariance of linear motion 92 | Q_rot = eye(6,6); % a substitute matrix for the covariance of the rotational motion (it will be computed in the filter at each recursion) 93 | Q_extent = zeros(numBasisAngles); % predicted covariance of the extent will be computed within the filter according to Eqn. 20 94 | Q = blkdiag(Q_lin, Q_rot, Q_extent); 95 | 96 | processModel = {F, Q, lambda}; 97 | 98 | 99 | %% Open a Figure (to illustrate the tracking outputs) 100 | figure; 101 | grid on; hold on; axis equal; 102 | view(45, 25); 103 | title('Extended Target Tracking Results'); 104 | xlabel('X axis'); 105 | ylabel('Y axis'); 106 | zlabel('Z axis'); 107 | 108 | 109 | %% GPETT3D LOOP 110 | time = 0; 111 | numInstants = ceil(expDuration/ T); 112 | filterParam = {processModel, paramGP, basisAngleArray, T, stdAngVel, eps}; 113 | 114 | for k = 1:numInstants 115 | 116 | % Extract current measurements 117 | curMeasArray = measComplete(abs(measComplete(:, 1)-time)