2017-07-19 197 views
1

我需要计算两个平面之间的角度。一架飞机是手机,另一架是前臂飞机。我计算了这些飞机的法线,并在MATLAB中使用了公式atan2(norm(cross(var.n1,var.n2)),dot(var.n1,var.n2));。我希望看到以正峰值和负峰值为特征的手腕的屈曲/伸展角度,但通过这个公式,我只能得到正峰值。Matlab atan2两个3D矢量之间的角度

%% Script to compute the angles of wrist flexion/extension and adduction/abduction based on Vicon data 
% REF: Cheryl et al., March 2008 
% Order of the markers: 1.WRR 2.WRU 3.FAU 4.FAR 5.CMC2 6.CMC5 7.MCP5 8.MCP2 

clc 
close all 
clear all 

%% Initialization 
% dir_kinematic = input('Path of the folder containing the kinematic files: ','s'); 
dir_kinematic = 'C:\Users\Utente\Desktop\TESI\Vicon\test.mat'; 
cd(dir_kinematic); 

fileList = getAllFiles(dir_kinematic,0); % Get names of all kinematic files 
f=1; 
%% Conversion to angles 
for f = 1:length(fileList) 
    if ~isempty(strfind(fileList{f},'mat')) % Take only mat files 


     % 0. Loading 
     load(fileList{f}); 

     % 1. Filtering 
     frameRate = kinematic.framerate; 
     n = 9; 
     Wn = 2/(frameRate/2); 
     ftype = 'low'; 
     [b,a] = butter(n,Wn,ftype); 
     kinematic.x = filtfilt(b,a,kinematic.x); 
     kinematic.y = filtfilt(b,a,kinematic.y); 
     kinematic.z = filtfilt(b,a,kinematic.z); 


     % 2. Create vectors 
     var.n=length(kinematic.x); 

     % Forearm plane 
     var.FAU_WRU=[kinematic.x(:,2)-kinematic.x(:,3),kinematic.y(:,2)-kinematic.y(:,3),kinematic.z(:,2)-kinematic.z(:,3)]; 
     var.WRR_WRU=[kinematic.x(:,2)-kinematic.x(:,1),kinematic.y(:,2)-kinematic.y(:,1),kinematic.z(:,2)-kinematic.z(:,1)]; 

     % Hand plane 
     var.CMC5_MCP5=[kinematic.x(:,7)-kinematic.x(:,6),kinematic.y(:,7)-kinematic.y(:,6),kinematic.z(:,7)-kinematic.z(:,6)]; 
     var.MCP2_MCP5=[kinematic.x(:,7)-kinematic.x(:,8),kinematic.y(:,7)-kinematic.y(:,8),kinematic.z(:,7)-kinematic.z(:,8)]; 

     % Transpose 
     var.FAU_WRU = var.FAU_WRU'; 
     var.WRR_WRU = var.WRR_WRU'; 
     var.CMC5_MCP5 = var.CMC5_MCP5'; 
     var.MCP2_MCP5 = var.MCP2_MCP5'; 

     % 3. Calculate angle of wrist flexion/extension 
     % Cross vector function for all time => create normal vector plane 
     var.forearm_n=[]; 
     var.hand_n=[]; 
     var.theta_rad=[]; 

     for i = 1:var.n % Loop through experiment 

      % vector x and y of the forearm plane 
      var.v1=var.FAU_WRU(:,i); % take x,y,z of the vector for every time 
      var.v2=var.WRR_WRU(:,i); 

      % vector x and y of the hand plane 
      var.v3=var.CMC5_MCP5(:,i); 
      var.v4=var.MCP2_MCP5(:,i); 

      var.forearm_n= [var.forearm_n, cross(var.v1,var.v2)]; 
      var.hand_n=[var.hand_n, cross(var.v3,var.v4)]; 

     end 

     % Calculate angle 
     for i = 1:var.n 

      var.n1=(var.forearm_n(:,i)); 
      var.n2=var.hand_n(:,i); 

      var.scalar_product(i) = dot(var.n1,var.n2); 

      %Equation (2) of the paper 
      var.theta_rad=[var.theta_rad, atan2(norm(cross(var.n1,var.n2)),dot(var.n1,var.n2))]; % result in radian 

      angle.flex_deflex_wrist{f}=(var.theta_rad*180)/pi; 

     end 

     % 4. Calculate angle of wrist adduction/abduction 

     % Projection vector onto plane 

     var.MCP2_MCP5_forearmproj=[]; 
     var.WRR_WRU_forearmproj=[]; 
     var.rad_ul_angle_rad=[]; 

     for i=1:var.n 

      %take x,y,z of the vector for each time 
      var.v1=var.MCP2_MCP5(:,i); 
      var.v2=var.WRR_WRU(:,i); 

      % vector x and y of the forearm plane 
      var.vfx=var.FAU_WRU(:,i); % take x,y,z of the vector for every time 
      var.vfy=var.WRR_WRU(:,i); 

      %projection of vector MCP2_MCP5 and WRR_WRU onto forearm plane 
      var.squNorm1=(norm(var.vfx)*norm(var.vfx)); 
      var.squNorm2=(norm(var.vfy)*norm(var.vfy)); 

      var.MCP2_MCP5_forearmproj=[var.MCP2_MCP5_forearmproj,((((var.v1')*var.vfx)*var.vfx/var.squNorm1)+(((var.v1')*var.vfy)*var.vfy/var.squNorm2))]; 
      var.WRR_WRU_forearmproj=[var.WRR_WRU_forearmproj,((var.vfx*((var.v2')*var.vfx/var.squNorm1))+(var.vfy*((var.v2')*var.vfy/var.squNorm2)))]; 
     end 

     % Calculate angle 

     for i=1:var.n 

      var.n1=var.MCP2_MCP5_forearmproj(:,i)'; 
      var.n2=var.WRR_WRU_forearmproj(:,i); 
      var.product=var.n1*var.n2; 

      var.rad_ul_angle_rad=[var.rad_ul_angle_rad, atan2(norm(cross(var.n1,var.n2)),dot(var.n1,var.n2))];% en rad 
      angle.rad_ul_wrist{f}=(var.rad_ul_angle_rad*180)/pi; 
     end 

    end 
end 

我想知道为什么我的角度始终为正?我需要看到积极和消极的峰... 感谢您的帮助!

回答

1

由于两个平面之间的角度与它的法线之间的角度相同,我将限制讨论两个矢量之间的角度。

我们知道,两个向量(一个b)之间的叉积是另一个向量,垂直于它们两者。

我们正在处理区分角度-T和+ T的问题,其中T是某个角度。

使用你所使用的公式,这两个角度会产生相同的结果,由于所使用的基本公式本身: ATAN2(| AXB |,AB)

这是因为,虽然AB是相同的在两种情况下,axb都不同,恰好为,这两个向量的法线符号相同,也没有别的(用手规则验证自己)。当我们计算这个向量的规范时,关于它的符号的信息丢失了,因为函数总是返回正值。

你可以做些什么

你需要保持一个X B的标志的跟踪,以确定该角度是正还是负。

注意:由于我在手机上回复,我无法添加更好的格式或代码,因此很快会更新答案。