GPS地理坐标与ros右手坐标系的转换

最近又关注到一个问题,gps的航向与ros标准航向之间的转换。

地理方位角与数学角度转换分析

概述

在车辆轨迹分析和导航系统中,经常需要处理两种不同的角度表示系统:地理方位角(Geographic Azimuth)和数学角度(Mathematical Angle)。这两种系统在基准方向和角度增长方向上存在根本差异,需要进行适当的转换才能确保数据的一致性和准确性。

本文档通过理论分析和可视化图表,详细说明了这两种角度系统的特点、转换原理以及在实际应用中的效果。

1. 两种角度系统的定义

1.1 地理方位角系统(Geographic Azimuth System)

  • 基准方向:北方(North)为 0°
  • 角度增长方向:顺时针(Clockwise)
  • 角度范围:通常为 0° ~ 360°
  • 应用场景:GPS导航、地理信息系统、航海航空

方向对应关系:

  • 北方(North):0°
  • 东方(East):90°
  • 南方(South):180°
  • 西方(West):270°

1.2 数学角度系统(Mathematical Angle System)

  • 基准方向:东方(East)为 0°
  • 角度增长方向:逆时针(Counter-clockwise)
  • 角度范围:通常为 -180° ~ 180° 或 0° ~ 360°
  • 应用场景:数学计算、物理学、计算机图形学

方向对应关系:

  • 东方(East):0°
  • 北方(North):90°
  • 西方(West):180° 或 -180°
  • 南方(South):-90° 或 270°

2. 坐标系对比可视化

在这里插入图片描述

上图展示了两种坐标系的直观对比:

  • 左图:地理方位角系统,以北为0°基准,顺时针增长
  • 右图:数学角度系统,以东为0°基准,逆时针增长

3. 转换公式推导

3.1 基本转换公式

从地理方位角转换为数学角度的公式为:

math_angle = 90° - geo_angle

3.2 公式推导过程

  1. 坐标轴旋转:地理方位角以北为0°,数学角度以东为0°,需要进行90°的坐标轴旋转
  2. 方向反转:地理方位角顺时针增长,数学角度逆时针增长,需要反转方向
  3. 组合变换:90° - geo_angle 同时实现了坐标轴旋转和方向反转

3.3 角度范围调整

转换后需要将角度调整到合适的范围:

# 调整到 [-180°, 180°] 范围
while math_angle > 180:
    math_angle -= 360
while math_angle < -180:
    math_angle += 360

4. 角度转换效果分析

4.1 转换曲线对比

在这里插入图片描述

该图展示了:

  • 原始地理方位角的变化规律(0°-360°)
  • 转换后数学角度的变化规律(-180°~180°)
  • 两种角度系统的对应关系

4.2 角度差异分布

在这里插入图片描述

左图显示了转换前后角度差异的分布特征,右图展示了两种角度系统的散点关系,验证了转换公式的正确性。

5. 几何变换原理

5.1 变换示意图

在这里插入图片描述

该图详细展示了:

  • 两种坐标系的向量表示
  • 转换公式的几何意义
  • 主要方向的角度对应关系
  • 完整的角度对应表

5.2 变换的几何意义

转换公式 math_angle = 90° - geo_angle 的几何意义包括:

  1. 坐标轴重新定位:将北方向(0°)重新定位到东方向(0°)
  2. 方向反转:将顺时针方向转换为逆时针方向
  3. 组合变换:一个公式同时实现两种变换

6. 实际应用效果

6.1 轨迹数据转换

在这里插入图片描述

该图展示了在实际轨迹数据中的转换效果:

  • 左上:模拟的车辆轨迹路径
  • 右上:三种角度数据的对比(真实角度、地理方位角、转换后角度)
  • 左下:转换误差分析
  • 右下:误差分布直方图

6.2 转换精度分析

通过实际数据验证,转换公式的效果显著:

  • 转换前:原始地理方位角与计算角度的平均差异约为 89.3°
  • 转换后:修正后角度与计算角度的平均差异降至 0.5°
  • 最大误差:从 179.7° 降至 14.4°

7. 代码实现

7.1 Python实现示例

import numpy as np

def convert_geo_to_math_angle(geo_angle):
    """
    将地理方位角转换为数学角度
    
    Args:
        geo_angle: 地理方位角 (0-360度)
    
    Returns:
        math_angle: 数学角度 (-180到180度)
    """
    # 基本转换公式
    math_angle = 90.0 - geo_angle
    
    # 调整到 [-180, 180] 范围
    while math_angle > 180:
        math_angle -= 360
    while math_angle < -180:
        math_angle += 360
    
    return math_angle

# 批量转换示例
def batch_convert_angles(geo_angles):
    """
    批量转换地理方位角为数学角度
    """
    math_angles = 90.0 - np.array(geo_angles)
    
    # 调整角度范围
    math_angles = np.where(math_angles > 180, math_angles - 360, math_angles)
    math_angles = np.where(math_angles < -180, math_angles + 360, math_angles)
    
    return math_angles

7.2 ROS2节点中的应用

trajectory_visualizer.py 中的实际应用:

# 修正原始航向角:从地理方位角转换为数学角度
corrected_original_headings = []
for heading in original_headings:
    # 转换为数学角度
    corrected_heading = 90.0 - heading
    
    # 调整到 [-180, 180] 范围
    while corrected_heading > 180:
        corrected_heading -= 360
    while corrected_heading < -180:
        corrected_heading += 360
        
    corrected_original_headings.append(corrected_heading)

9. 性能优化建议

9.1 批量处理

对于大量数据,使用NumPy进行向量化操作:

# 向量化转换,性能更好
math_angles = 90.0 - geo_angles
math_angles = np.where(math_angles > 180, math_angles - 360, math_angles)
math_angles = np.where(math_angles < -180, math_angles + 360, math_angles)

9.2 预计算查找表

对于实时系统,可以预计算查找表:

# 创建查找表(精度为0.1度)
lookup_table = {}
for geo_angle in np.arange(0, 360, 0.1):
    math_angle = convert_geo_to_math_angle(geo_angle)
    lookup_table[round(geo_angle, 1)] = math_angle

10. 总结

地理方位角与数学角度的转换是导航和定位系统中的基础问题。通过本文的分析可以得出:

  1. 转换公式简单有效math_angle = 90° - geo_angle 能够准确实现两种角度系统的转换
  2. 几何意义明确:公式同时实现了坐标轴旋转和方向反转
  3. 应用效果显著:转换后的角度与理论计算值高度一致
  4. 实现方式灵活:可根据具体需求选择不同的实现方式

正确理解和应用这种转换关系,对于确保导航系统的准确性和可靠性具有重要意义。


可视化程序使用说明

本分析文档配套的可视化程序 coordinate_visualization.py 可以生成所有相关图表:

# 运行可视化程序
python3 coordinate_visualization.py
#!/usr/bin/env python3
"""
坐标系转换可视化程序
用于演示地理方位角与数学角度转换的原理和效果
"""

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.patches import FancyArrowPatch
import os
from datetime import datetime

class CoordinateSystemVisualizer:
    def __init__(self):
        # 创建输出目录
        self.output_dir = '/home/cyun/Fork_RL/9.4/forklift_rl/catkin_ws/analysis_plots'
        os.makedirs(self.output_dir, exist_ok=True)
        
        # 设置中文字体支持
        plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        
        print(f"可视化程序初始化完成,输出目录: {self.output_dir}")
    
    def generate_theoretical_data(self, num_points=36):
        """生成理论数据用于演示"""
        # 生成0-360度的角度数据
        geo_angles = np.linspace(0, 360, num_points, endpoint=False)
        
        # 转换为数学角度
        math_angles = 90 - geo_angles
        
        # 调整到[-180, 180]范围
        math_angles = np.where(math_angles > 180, math_angles - 360, math_angles)
        math_angles = np.where(math_angles < -180, math_angles + 360, math_angles)
        
        return geo_angles, math_angles
    
    def plot_coordinate_systems_comparison(self):
        """绘制两种坐标系的对比图(极坐标图)"""
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8), subplot_kw=dict(projection='polar'))
        
        # 生成角度数据
        angles = np.linspace(0, 2*np.pi, 8, endpoint=False)
        
        # 地理方位角系统(左图)
        ax1.set_theta_zero_location('N')  # 北为0度
        ax1.set_theta_direction(-1)       # 顺时针
        
        # 绘制主要方向
        directions_geo = ['N (0°)', 'NE (45°)', 'E (90°)', 'SE (135°)', 
                         'S (180°)', 'SW (225°)', 'W (270°)', 'NW (315°)']
        
        for i, (angle, label) in enumerate(zip(angles, directions_geo)):
            ax1.arrow(0, 0, angle, 1, head_width=0.1, head_length=0.1, 
                     fc='blue', ec='blue', alpha=0.7)
            ax1.text(angle, 1.2, label, ha='center', va='center', fontsize=10)
        
        ax1.set_ylim(0, 1.5)
        ax1.set_title('Geographic Azimuth System\n(North=0°, Clockwise)', 
                     fontsize=14, fontweight='bold', pad=20)
        ax1.grid(True)
        
        # 数学角度系统(右图)
        ax2.set_theta_zero_location('E')  # 东为0度
        ax2.set_theta_direction(1)        # 逆时针
        
        # 绘制主要方向
        directions_math = ['E (0°)', 'NE (45°)', 'N (90°)', 'NW (135°)', 
                          'W (180°)', 'SW (-135°)', 'S (-90°)', 'SE (-45°)']
        
        for i, (angle, label) in enumerate(zip(angles, directions_math)):
            ax2.arrow(0, 0, angle, 1, head_width=0.1, head_length=0.1, 
                     fc='red', ec='red', alpha=0.7)
            ax2.text(angle, 1.2, label, ha='center', va='center', fontsize=10)
        
        ax2.set_ylim(0, 1.5)
        ax2.set_title('Mathematical Angle System\n(East=0°, Counter-clockwise)', 
                     fontsize=14, fontweight='bold', pad=20)
        ax2.grid(True)
        
        plt.tight_layout()
        
        # 保存图片
        filename = 'coordinate_systems_comparison.png'
        filepath = os.path.join(self.output_dir, filename)
        plt.savefig(filepath, dpi=300, bbox_inches='tight')
        print(f"坐标系对比图已保存: {filepath}")
        
        plt.show()
        plt.close()
    
    def plot_angle_conversion_curves(self):
        """绘制角度转换对比曲线图"""
        geo_angles, math_angles = self.generate_theoretical_data(72)
        
        fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 12))
        
        # 原始地理方位角
        ax1.plot(range(len(geo_angles)), geo_angles, 'b-', linewidth=2, 
                marker='o', markersize=4, label='Geographic Azimuth')
        ax1.set_ylabel('Angle (degrees)')
        ax1.set_title('Geographic Azimuth Angles (0°-360°)')
        ax1.grid(True, alpha=0.3)
        ax1.legend()
        ax1.set_ylim(-10, 370)
        
        # 转换后的数学角度
        ax2.plot(range(len(math_angles)), math_angles, 'r-', linewidth=2, 
                marker='s', markersize=4, label='Mathematical Angle')
        ax2.set_ylabel('Angle (degrees)')
        ax2.set_title('Converted Mathematical Angles (-180° to 180°)')
        ax2.grid(True, alpha=0.3)
        ax2.legend()
        ax2.set_ylim(-190, 190)
        
        # 对比图
        ax3.plot(range(len(geo_angles)), geo_angles, 'b-', linewidth=2, 
                marker='o', markersize=3, alpha=0.7, label='Geographic Azimuth')
        ax3.plot(range(len(math_angles)), math_angles, 'r-', linewidth=2, 
                marker='s', markersize=3, alpha=0.7, label='Mathematical Angle')
        ax3.set_xlabel('Data Point Index')
        ax3.set_ylabel('Angle (degrees)')
        ax3.set_title('Angle Conversion Comparison')
        ax3.grid(True, alpha=0.3)
        ax3.legend()
        
        plt.tight_layout()
        
        # 保存图片
        filename = 'angle_conversion_curves.png'
        filepath = os.path.join(self.output_dir, filename)
        plt.savefig(filepath, dpi=300, bbox_inches='tight')
        print(f"角度转换曲线图已保存: {filepath}")
        
        plt.show()
        plt.close()
    
    def plot_angle_difference_histogram(self):
        """绘制角度差异分布直方图"""
        geo_angles, math_angles = self.generate_theoretical_data(360)
        
        # 计算角度差异
        angle_diff = np.array(geo_angles) - np.array(math_angles)
        
        # 处理角度差异的周期性
        angle_diff = np.where(angle_diff > 180, angle_diff - 360, angle_diff)
        angle_diff = np.where(angle_diff < -180, angle_diff + 360, angle_diff)
        
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
        
        # 角度差异直方图
        ax1.hist(angle_diff, bins=30, alpha=0.7, color='green', edgecolor='black')
        ax1.set_xlabel('Angle Difference (degrees)')
        ax1.set_ylabel('Frequency')
        ax1.set_title('Distribution of Angle Differences\n(Geographic - Mathematical)')
        ax1.grid(True, alpha=0.3)
        
        # 添加统计信息
        mean_diff = np.mean(angle_diff)
        std_diff = np.std(angle_diff)
        ax1.axvline(mean_diff, color='red', linestyle='--', linewidth=2, 
                   label=f'Mean: {mean_diff:.1f}°')
        ax1.axvline(mean_diff + std_diff, color='orange', linestyle=':', 
                   label=f'±1σ: {std_diff:.1f}°')
        ax1.axvline(mean_diff - std_diff, color='orange', linestyle=':')
        ax1.legend()
        
        # 散点图显示转换关系
        ax2.scatter(geo_angles, math_angles, alpha=0.6, s=20, c='purple')
        ax2.set_xlabel('Geographic Azimuth (degrees)')
        ax2.set_ylabel('Mathematical Angle (degrees)')
        ax2.set_title('Geographic vs Mathematical Angle Relationship')
        ax2.grid(True, alpha=0.3)
        
        # 添加转换公式
        ax2.text(0.05, 0.95, 'Conversion Formula:\nmath_angle = 90° - geo_angle', 
                transform=ax2.transAxes, fontsize=12, 
                bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8),
                verticalalignment='top')
        
        plt.tight_layout()
        
        # 保存图片
        filename = 'angle_difference_histogram.png'
        filepath = os.path.join(self.output_dir, filename)
        plt.savefig(filepath, dpi=300, bbox_inches='tight')
        print(f"角度差异分布图已保存: {filepath}")
        
        plt.show()
        plt.close()
    
    def plot_geometric_transformation(self):
        """绘制几何变换示意图(向量图)"""
        fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
        
        # 示例角度
        example_angles = [0, 45, 90, 135, 180, 225, 270, 315]
        colors = ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'pink']
        
        # 地理方位角系统
        ax1.set_xlim(-1.5, 1.5)
        ax1.set_ylim(-1.5, 1.5)
        ax1.set_aspect('equal')
        ax1.grid(True, alpha=0.3)
        ax1.set_title('Geographic Azimuth System\n(North=0°, Clockwise)', fontweight='bold')
        
        # 绘制坐标轴
        ax1.arrow(0, 0, 0, 1.3, head_width=0.05, head_length=0.05, fc='black', ec='black')
        ax1.arrow(0, 0, 1.3, 0, head_width=0.05, head_length=0.05, fc='black', ec='black')
        ax1.text(0, 1.4, 'N (0°)', ha='center', va='bottom', fontweight='bold')
        ax1.text(1.4, 0, 'E (90°)', ha='left', va='center', fontweight='bold')
        
        # 绘制方向向量
        for i, (angle, color) in enumerate(zip(example_angles, colors)):
            # 地理方位角:北为0度,顺时针
            rad = np.radians(angle)
            x = np.sin(rad)  # 地理方位角中,x对应东方向
            y = np.cos(rad)  # y对应北方向
            
            ax1.arrow(0, 0, x, y, head_width=0.05, head_length=0.05, 
                     fc=color, ec=color, alpha=0.8, linewidth=2)
            ax1.text(x*1.2, y*1.2, f'{angle}°', ha='center', va='center', 
                    fontsize=10, fontweight='bold')
        
        # 数学角度系统
        ax2.set_xlim(-1.5, 1.5)
        ax2.set_ylim(-1.5, 1.5)
        ax2.set_aspect('equal')
        ax2.grid(True, alpha=0.3)
        ax2.set_title('Mathematical Angle System\n(East=0°, Counter-clockwise)', fontweight='bold')
        
        # 绘制坐标轴
        ax2.arrow(0, 0, 1.3, 0, head_width=0.05, head_length=0.05, fc='black', ec='black')
        ax2.arrow(0, 0, 0, 1.3, head_width=0.05, head_length=0.05, fc='black', ec='black')
        ax2.text(1.4, 0, 'E (0°)', ha='left', va='center', fontweight='bold')
        ax2.text(0, 1.4, 'N (90°)', ha='center', va='bottom', fontweight='bold')
        
        # 绘制转换后的方向向量
        for i, (geo_angle, color) in enumerate(zip(example_angles, colors)):
            # 转换为数学角度
            math_angle = 90 - geo_angle
            if math_angle > 180:
                math_angle -= 360
            elif math_angle < -180:
                math_angle += 360
            
            rad = np.radians(math_angle)
            x = np.cos(rad)  # 数学角度中,x对应东方向
            y = np.sin(rad)  # y对应北方向
            
            ax2.arrow(0, 0, x, y, head_width=0.05, head_length=0.05, 
                     fc=color, ec=color, alpha=0.8, linewidth=2)
            ax2.text(x*1.2, y*1.2, f'{math_angle}°', ha='center', va='center', 
                    fontsize=10, fontweight='bold')
        
        # 转换公式示意图
        ax3.set_xlim(0, 10)
        ax3.set_ylim(0, 8)
        ax3.axis('off')
        ax3.set_title('Conversion Formula Explanation', fontweight='bold')
        
        # 添加公式说明
        formula_text = [
            "Conversion Formula:",
            "math_angle = 90° - geo_angle",
            "",
            "Geometric Meaning:",
            "1. Coordinate axis rotation: 90° rotation",
            "2. Direction reversal: clockwise → counter-clockwise",
            "3. Combined transformation",
            "",
            "Examples:",
            "• North (geo: 0°) → North (math: 90°)",
            "• East (geo: 90°) → East (math: 0°)",
            "• South (geo: 180°) → South (math: -90°)",
            "• West (geo: 270°) → West (math: -180°)"
        ]
        
        for i, text in enumerate(formula_text):
            if text.startswith("Conversion") or text.startswith("Geometric") or text.startswith("Examples"):
                ax3.text(0.5, 7.5-i*0.5, text, fontsize=12, fontweight='bold')
            elif text.startswith("math_angle"):
                ax3.text(0.5, 7.5-i*0.5, text, fontsize=14, fontweight='bold', 
                        bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.8))
            else:
                ax3.text(0.5, 7.5-i*0.5, text, fontsize=11)
        
        # 角度对应表
        ax4.set_xlim(0, 10)
        ax4.set_ylim(0, 10)
        ax4.axis('off')
        ax4.set_title('Angle Correspondence Table', fontweight='bold')
        
        # 创建表格
        table_data = [
            ["Direction", "Geographic", "Mathematical"],
            ["North", "0°", "90°"],
            ["Northeast", "45°", "45°"],
            ["East", "90°", "0°"],
            ["Southeast", "135°", "-45°"],
            ["South", "180°", "-90°"],
            ["Southwest", "225°", "-135°"],
            ["West", "270°", "180°"],
            ["Northwest", "315°", "135°"]
        ]
        
        for i, row in enumerate(table_data):
            for j, cell in enumerate(row):
                if i == 0:  # 表头
                    ax4.text(j*3+1, 9-i*0.8, cell, fontsize=12, fontweight='bold',
                            ha='center', va='center',
                            bbox=dict(boxstyle='round', facecolor='lightgray', alpha=0.8))
                else:
                    ax4.text(j*3+1, 9-i*0.8, cell, fontsize=11, ha='center', va='center')
        
        plt.tight_layout()
        
        # 保存图片
        filename = 'geometric_transformation.png'
        filepath = os.path.join(self.output_dir, filename)
        plt.savefig(filepath, dpi=300, bbox_inches='tight')
        print(f"几何变换示意图已保存: {filepath}")
        
        plt.show()
        plt.close()
    
    def plot_trajectory_conversion_effect(self):
        """绘制实际轨迹数据的角度转换效果图"""
        # 模拟实际轨迹数据
        t = np.linspace(0, 4*np.pi, 100)
        
        # 生成螺旋轨迹的UTM坐标
        x = t * np.cos(t) * 10
        y = t * np.sin(t) * 10
        
        # 计算真实的数学角度(基于轨迹方向)
        dx = np.diff(x)
        dy = np.diff(y)
        true_math_angles = np.arctan2(dy, dx) * 180 / np.pi
        
        # 模拟地理方位角数据(添加一些噪声和偏移)
        simulated_geo_angles = 90 - true_math_angles + np.random.normal(0, 5, len(true_math_angles))
        simulated_geo_angles = np.where(simulated_geo_angles < 0, simulated_geo_angles + 360, simulated_geo_angles)
        simulated_geo_angles = np.where(simulated_geo_angles >= 360, simulated_geo_angles - 360, simulated_geo_angles)
        
        # 转换地理方位角为数学角度
        converted_math_angles = 90 - simulated_geo_angles
        converted_math_angles = np.where(converted_math_angles > 180, converted_math_angles - 360, converted_math_angles)
        converted_math_angles = np.where(converted_math_angles < -180, converted_math_angles + 360, converted_math_angles)
        
        fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(16, 12))
        
        # 轨迹路径图
        ax1.plot(x, y, 'b-', linewidth=2, alpha=0.8)
        ax1.scatter(x[::10], y[::10], c=range(0, len(x), 10), cmap='viridis', s=30, alpha=0.8)
        ax1.set_xlabel('UTM X (m)')
        ax1.set_ylabel('UTM Y (m)')
        ax1.set_title('Simulated Vehicle Trajectory')
        ax1.grid(True, alpha=0.3)
        ax1.set_aspect('equal')
        
        # 添加方向箭头
        for i in range(0, len(x)-1, 15):
            ax1.arrow(x[i], y[i], dx[i]*2, dy[i]*2, 
                     head_width=3, head_length=5, fc='red', ec='red', alpha=0.7)
        
        # 角度对比图
        indices = range(len(true_math_angles))
        ax2.plot(indices, true_math_angles, 'g-', linewidth=2, label='True Mathematical Angle', alpha=0.8)
        ax2.plot(indices, simulated_geo_angles, 'b--', linewidth=1.5, label='Simulated Geographic Azimuth', alpha=0.7)
        ax2.plot(indices, converted_math_angles, 'r:', linewidth=2, label='Converted Mathematical Angle', alpha=0.8)
        ax2.set_xlabel('Trajectory Point Index')
        ax2.set_ylabel('Angle (degrees)')
        ax2.set_title('Angle Conversion in Real Trajectory Data')
        ax2.grid(True, alpha=0.3)
        ax2.legend()
        
        # 转换误差分析
        conversion_error = converted_math_angles - true_math_angles
        conversion_error = np.where(conversion_error > 180, conversion_error - 360, conversion_error)
        conversion_error = np.where(conversion_error < -180, conversion_error + 360, conversion_error)
        
        ax3.plot(indices, conversion_error, 'purple', linewidth=2, alpha=0.8)
        ax3.axhline(y=0, color='black', linestyle='-', alpha=0.5)
        ax3.fill_between(indices, conversion_error, alpha=0.3, color='purple')
        ax3.set_xlabel('Trajectory Point Index')
        ax3.set_ylabel('Conversion Error (degrees)')
        ax3.set_title('Angle Conversion Error Analysis')
        ax3.grid(True, alpha=0.3)
        
        # 添加统计信息
        mean_error = np.mean(np.abs(conversion_error))
        max_error = np.max(np.abs(conversion_error))
        ax3.text(0.02, 0.98, f'Mean Error: {mean_error:.2f}°\nMax Error: {max_error:.2f}°', 
                transform=ax3.transAxes, fontsize=12, 
                bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8),
                verticalalignment='top')
        
        # 误差分布直方图
        ax4.hist(conversion_error, bins=20, alpha=0.7, color='orange', edgecolor='black')
        ax4.set_xlabel('Conversion Error (degrees)')
        ax4.set_ylabel('Frequency')
        ax4.set_title('Distribution of Conversion Errors')
        ax4.grid(True, alpha=0.3)
        
        # 添加统计线
        ax4.axvline(np.mean(conversion_error), color='red', linestyle='--', linewidth=2, 
                   label=f'Mean: {np.mean(conversion_error):.2f}°')
        ax4.axvline(np.std(conversion_error), color='orange', linestyle=':', 
                   label=f'Std: {np.std(conversion_error):.2f}°')
        ax4.axvline(-np.std(conversion_error), color='orange', linestyle=':')
        ax4.legend()
        
        plt.tight_layout()
        
        # 保存图片
        filename = 'trajectory_conversion_effect.png'
        filepath = os.path.join(self.output_dir, filename)
        plt.savefig(filepath, dpi=300, bbox_inches='tight')
        print(f"轨迹转换效果图已保存: {filepath}")
        
        plt.show()
        plt.close()
    
    def generate_all_visualizations(self):
        """生成所有可视化图表"""
        print("开始生成坐标系转换分析图表...")
        
        print("\n1. 生成坐标系对比图...")
        self.plot_coordinate_systems_comparison()
        
        print("\n2. 生成角度转换曲线图...")
        self.plot_angle_conversion_curves()
        
        print("\n3. 生成角度差异分布图...")
        self.plot_angle_difference_histogram()
        
        print("\n4. 生成几何变换示意图...")
        self.plot_geometric_transformation()
        
        print("\n5. 生成轨迹转换效果图...")
        self.plot_trajectory_conversion_effect()
        
        print(f"\n所有图表已生成完成!输出目录: {self.output_dir}")
        
        # 列出生成的文件
        files = os.listdir(self.output_dir)
        print("\n生成的图表文件:")
        for file in sorted(files):
            if file.endswith('.png'):
                print(f"  - {file}")

def main():
    """主函数"""
    visualizer = CoordinateSystemVisualizer()
    visualizer.generate_all_visualizations()

if __name__ == '__main__':
    main()

程序将在 analysis_plots/ 目录下生成以下图表:

  • coordinate_systems_comparison.png:坐标系对比图
  • angle_conversion_curves.png:角度转换曲线图
  • angle_difference_histogram.png:角度差异分布图
  • geometric_transformation.png:几何变换示意图
  • trajectory_conversion_effect.png:轨迹转换效果图
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白云千载尽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值