radar_data_processor.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. """
  2. 基于XML配置的雷达数据处理器示例
  3. 使用XML配置文件来定义数据格式和处理参数
  4. 示例数据格式(CSV):
  5. 1234567.89,1,15.6,12.3,30.5,-15.2
  6. 1234567.90,2,25.1,8.7,-15.3,-12.8
  7. """
  8. from pathlib import Path
  9. import pandas as pd
  10. from typing import Dict, Any, Optional
  11. import tempfile
  12. import zipfile
  13. import xml.etree.ElementTree as ET
  14. import numpy as np
  15. from core.plugin_interface import CustomDataProcessorPlugin
  16. class RadarDataProcessor(CustomDataProcessorPlugin):
  17. """处理雷达数据的插件,使用XML配置文件"""
  18. def __init__(self):
  19. """初始化插件,加载XML配置文件"""
  20. self.config = None
  21. self.config_path = Path("resources/radar_config.xml")
  22. self.field_map = {}
  23. self.delimiter = ','
  24. self.processing_params = {}
  25. self.columns = ['simTime', 'target_id', 'distance', 'velocity', 'angle', 'rcs'] # 移除 frame
  26. self._load_config()
  27. def _load_config(self):
  28. """加载并解析XML配置文件"""
  29. try:
  30. if not self.config_path.exists():
  31. print(f"配置文件未找到: {self.config_path}")
  32. return
  33. tree = ET.parse(self.config_path)
  34. root = tree.getroot()
  35. # 解析字段配置
  36. fields = root.find('./DataFormat/Fields')
  37. if fields is not None:
  38. for field in fields.findall('Field'):
  39. name = field.get('name')
  40. column = int(field.get('column'))
  41. dtype = field.get('type')
  42. self.field_map[column] = {
  43. 'name': name,
  44. 'type': dtype,
  45. 'unit': field.get('unit', '')
  46. }
  47. # 解析分隔符
  48. delimiter = root.find('./DataFormat/Delimiter')
  49. if delimiter is not None:
  50. self.delimiter = delimiter.text
  51. # 解析处理参数
  52. processing = root.find('./Processing')
  53. if processing is not None:
  54. # 解析时间格式
  55. time_format = processing.find('TimeFormat')
  56. if time_format is not None:
  57. self.processing_params['time_format'] = time_format.text
  58. # 解析角度范围
  59. angle_range = processing.find('AngleRange')
  60. if angle_range is not None:
  61. self.processing_params['angle_min'] = float(angle_range.find('Min').text)
  62. self.processing_params['angle_max'] = float(angle_range.find('Max').text)
  63. # 解析距离范围
  64. distance_range = processing.find('DistanceRange')
  65. if distance_range is not None:
  66. self.processing_params['distance_min'] = float(distance_range.find('Min').text)
  67. self.processing_params['distance_max'] = float(distance_range.find('Max').text)
  68. # 解析过滤器参数
  69. filters = processing.find('Filters')
  70. if filters is not None:
  71. min_rcs = filters.find('MinRCS')
  72. if min_rcs is not None:
  73. self.processing_params['min_rcs'] = float(min_rcs.text)
  74. print(f"成功加载雷达配置文件: {self.config_path}")
  75. except Exception as e:
  76. print(f"加载配置文件失败: {e}")
  77. import traceback
  78. traceback.print_exc()
  79. def can_handle(self, zip_path: Path, folder_name: str) -> bool:
  80. """检查是否是雷达数据文件夹"""
  81. # 修改判断逻辑,使其更灵活地匹配雷达数据文件夹
  82. return 'radar' in folder_name.lower()
  83. def get_required_columns(self) -> Dict[str, Any]:
  84. """定义输出数据的列和类型"""
  85. return {
  86. 'simTime': float, # 必需列
  87. 'playerId': int, # 必需列
  88. 'simFrame': int, # 必需列
  89. 'radar_distance': float, # 雷达距离
  90. 'radar_velocity': float, # 雷达速度
  91. 'radar_angle': float, # 雷达角度
  92. 'radar_rcs': float, # 雷达RCS
  93. }
  94. def _convert_timestamp(self, timestamp: float) -> float:
  95. """根据配置转换时间戳格式"""
  96. time_format = self.processing_params.get('time_format', 'unix_timestamp')
  97. if time_format == 'unix_timestamp':
  98. return timestamp
  99. # 添加其他时间格式的转换if需要
  100. return timestamp
  101. def _filter_data(self, df: pd.DataFrame) -> pd.DataFrame:
  102. """根据配置的参数过滤数据"""
  103. if df.empty:
  104. return df
  105. # 角度范围过滤
  106. angle_min = self.processing_params.get('angle_min', -float('inf'))
  107. angle_max = self.processing_params.get('angle_max', float('inf'))
  108. df = df[df['angle'].between(angle_min, angle_max)]
  109. # 距离范围过滤
  110. distance_min = self.processing_params.get('distance_min', 0)
  111. distance_max = self.processing_params.get('distance_max', float('inf'))
  112. df = df[df['distance'].between(distance_min, distance_max)]
  113. # RCS过滤
  114. min_rcs = self.processing_params.get('min_rcs', -float('inf'))
  115. df = df[df['rcs'] >= min_rcs]
  116. return df
  117. def _process_extracted_files(self, file_paths: list) -> Optional[pd.DataFrame]:
  118. """处理提取的雷达数据文件,直接存储到输出目录"""
  119. all_data = []
  120. frame_counter = 1
  121. for file_path in file_paths:
  122. try:
  123. if file_path.suffix.lower() == '.csv':
  124. # Read and process data
  125. df = pd.read_csv(file_path, delimiter=self.delimiter, header=None)
  126. if df.empty:
  127. continue
  128. df = df.iloc[:, :6]
  129. df.columns = ['simTime', 'target_id', 'distance', 'velocity', 'angle', 'rcs']
  130. # Add frame numbers and process data
  131. df['simFrame'] = range(frame_counter, frame_counter + len(df))
  132. frame_counter += len(df)
  133. # Round values for consistency
  134. for col in ['simTime', 'distance', 'velocity', 'angle', 'rcs']:
  135. df[col] = df[col].round(3)
  136. df['playerId'] = 1
  137. # Filter and rename columns
  138. filtered_df = self._filter_data(df)
  139. if not filtered_df.empty:
  140. filtered_df = filtered_df.rename(columns={
  141. 'distance': 'radar_distance',
  142. 'velocity': 'radar_velocity',
  143. 'angle': 'radar_angle',
  144. 'rcs': 'radar_rcs'
  145. })
  146. all_data.append(filtered_df)
  147. except Exception as e:
  148. print(f"处理文件失败: {file_path}: {e}")
  149. continue
  150. if not all_data:
  151. return None
  152. # Merge all data and sort by time
  153. final_df = pd.concat(all_data, ignore_index=True)
  154. final_df.sort_values('simTime', inplace=True)
  155. final_df['simFrame'] = range(1, len(final_df) + 1)
  156. # Ensure correct data types
  157. for col, dtype in self.get_required_columns().items():
  158. if col in final_df.columns:
  159. final_df[col] = final_df[col].astype(dtype)
  160. final_df.reset_index(drop=True, inplace=True)
  161. return final_df