增加SDK文档
This commit is contained in:
@@ -1,29 +1,872 @@
|
|||||||
# mil_sdk
|
# MIL SDK 文档
|
||||||
|
|
||||||
MIL (Model-in-the-Loop) SDK for reading simulation data from Excel files.
|
MIL SDK 是一个用于处理 MIL(Model-In-the-Loop)仿真数据的 Python 工具包,主要提供 Excel 数据文件的读取、解析、生成和更新功能。
|
||||||
|
|
||||||
## Installation
|
## 目录
|
||||||
|
|
||||||
|
- [概述](#概述)
|
||||||
|
- [项目架构](#项目架构)
|
||||||
|
- [快速开始](#快速开始)
|
||||||
|
- [数据模型](#数据模型)
|
||||||
|
- [异常体系](#异常体系)
|
||||||
|
- [日志模块](#日志模块)
|
||||||
|
- [Excel 读取模块](#excel-读取模块)
|
||||||
|
- [Excel 生成模块](#excel-生成模块)
|
||||||
|
- [Excel 更新模块](#excel-更新模块)
|
||||||
|
- [API 参考](#api-参考)
|
||||||
|
- [使用示例](#使用示例)
|
||||||
|
- [Excel 文件格式约定](#excel-文件格式约定)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
### 项目简介
|
||||||
|
|
||||||
|
MIL SDK 专为 MIL 仿真数据处理场景设计,提供以下核心能力:
|
||||||
|
|
||||||
|
- **数据读取** - 从特定格式的 Excel 文件中解析仿真信号数据
|
||||||
|
- **用例管理** - 读取和解析测试用例模板
|
||||||
|
- **用例生成** - 根据数据和模板生成测试用例 Excel 文件
|
||||||
|
- **数据对比** - 比较新旧仿真数据差异,自动更新信号列
|
||||||
|
|
||||||
|
### 技术栈
|
||||||
|
|
||||||
|
| 类别 | 技术选型 |
|
||||||
|
|------|----------|
|
||||||
|
| 语言 | Python 3.10+ |
|
||||||
|
| 主要依赖 | openpyxl >= 3.0.0 |
|
||||||
|
| 测试框架 | pytest >= 7.0.0 |
|
||||||
|
| 类型检查 | mypy >= 1.0.0 |
|
||||||
|
| 代码规范 | ruff >= 0.1.0 |
|
||||||
|
|
||||||
|
### 版本信息
|
||||||
|
|
||||||
|
- 当前版本:0.1.0
|
||||||
|
- 许可证:MIT
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 项目架构
|
||||||
|
|
||||||
|
### 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
mil_sdk/
|
||||||
|
├── src/
|
||||||
|
│ └── core/ # 核心模块
|
||||||
|
│ ├── __init__.py # 公共 API 导出
|
||||||
|
│ ├── base.py # 核心数据模型
|
||||||
|
│ ├── exceptions.py # 自定义异常
|
||||||
|
│ ├── logging_config.py # 日志配置
|
||||||
|
│ ├── mil_read_data_excel.py # 读取仿真数据 Excel
|
||||||
|
│ ├── mil_read_case_excel.py # 读取测试用例 Excel
|
||||||
|
│ ├── mil_create_data_excel.py # 生成测试用例 Excel
|
||||||
|
│ └── mil_update_excel.py # 更新用例 Excel
|
||||||
|
├── tests/ # 测试模块
|
||||||
|
│ ├── conftest.py # pytest 配置和 fixtures
|
||||||
|
│ ├── test_base.py # 基础数据模型测试
|
||||||
|
│ ├── test_mil_case_excel.py # 用例 Excel 测试
|
||||||
|
│ └── test_mil_data_excel.py # 数据 Excel 测试
|
||||||
|
├── main.py # 入口文件
|
||||||
|
├── pyproject.toml # 项目配置
|
||||||
|
├── requirements.txt # 依赖清单
|
||||||
|
└── SDK_DOCUMENTATION.md # 本文档
|
||||||
|
```
|
||||||
|
|
||||||
|
### 模块职责
|
||||||
|
|
||||||
|
| 模块 | 文件 | 职责 |
|
||||||
|
|------|------|------|
|
||||||
|
| 数据模型 | base.py | 定义 DataLog、SignalData、ExcelDataResult 等核心数据结构 |
|
||||||
|
| 异常体系 | exceptions.py | 定义 MILSDKError 及其子类,统一异常处理 |
|
||||||
|
| 日志模块 | logging_config.py | 提供日志配置和获取功能 |
|
||||||
|
| 数据读取 | mil_read_data_excel.py | 解析 MIL 仿真数据 Excel,提取信号数据 |
|
||||||
|
| 用例读取 | mil_read_case_excel.py | 解析测试用例模板 Excel |
|
||||||
|
| 用例生成 | mil_create_data_excel.py | 根据模板生成测试用例 Excel |
|
||||||
|
| 用例更新 | mil_update_excel.py | 比较新旧数据,更新信号列 |
|
||||||
|
|
||||||
|
### 依赖关系
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ main.py │
|
||||||
|
│ (入口文件,演示 SDK 使用) │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ src/core/__init__.py │
|
||||||
|
│ (公共 API 统一导出模块) │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
│ │ │ │ │
|
||||||
|
▼ ▼ ▼ ▼ ▼
|
||||||
|
┌────────┐ ┌──────┐ ┌────────┐ ┌──────┐ ┌──────┐
|
||||||
|
│ base │ │excep │ │logging│ │ mil_ │ │ mil_ │
|
||||||
|
│ │ │tions │ │_conf │ │read_ │ │create│
|
||||||
|
│ │ │ │ │ │ │data │ │_data │
|
||||||
|
└────────┘ └──────┘ └───────┘ └──────┘ └──────┘
|
||||||
|
│ │
|
||||||
|
▼ ▼
|
||||||
|
┌────────┐ ┌────────┐
|
||||||
|
│ mil_ │ │ mil_ │
|
||||||
|
│read_ │ │update_ │
|
||||||
|
│case │ │excel │
|
||||||
|
└────────┘ └────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 安装
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install -e .
|
pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
### 开发依赖安装
|
||||||
|
|
||||||
```python
|
|
||||||
from src.core import read_excel_data, DataLog
|
|
||||||
|
|
||||||
result = read_excel_data("path/to/simulation.xlsx")
|
|
||||||
print(result["signal1"]["datalog"]) # List[DataLog]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pytest tests/ -v
|
pip install -e ".[dev]"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Dependencies
|
### 基础使用
|
||||||
|
|
||||||
- Python >= 3.10
|
```python
|
||||||
- openpyxl >= 3.0.0
|
from src.core import setup_logging, read_excel_data, ExcelReaderConfig
|
||||||
|
|
||||||
|
# 初始化日志
|
||||||
|
setup_logging()
|
||||||
|
|
||||||
|
# 读取仿真数据
|
||||||
|
config = ExcelReaderConfig()
|
||||||
|
result = read_excel_data("simulation.xlsx", return_object=True, config=config)
|
||||||
|
|
||||||
|
# 获取信号数据
|
||||||
|
signal = result.get_signal("signal_name")
|
||||||
|
if signal:
|
||||||
|
for log in signal.datalog:
|
||||||
|
print(f"时间: {log.time}, 值: {log.value}")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 数据模型
|
||||||
|
|
||||||
|
### DataLog
|
||||||
|
|
||||||
|
仿真数据日志记录,表示单个时间点的数据。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class DataLog:
|
||||||
|
time: float = 0.0 # 时间戳(秒)
|
||||||
|
value: str = "" # 信号值
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性说明**:
|
||||||
|
|
||||||
|
| 属性 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| time | float | 0.0 | 时间戳,单位为秒 |
|
||||||
|
| value | str | "" | 信号值,可以是任意类型 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
log = DataLog(time=1.5, value="on")
|
||||||
|
print(f"时间: {log.time}, 值: {log.value}")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### SignalData
|
||||||
|
|
||||||
|
信号数据封装,包含信号的元数据和数据日志。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class SignalData:
|
||||||
|
column: int = 0 # 列索引
|
||||||
|
attributes: dict[str, str] = field(default_factory=dict) # 信号属性
|
||||||
|
datalog: list[DataLog] = field(default_factory=list) # 数据日志列表
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性说明**:
|
||||||
|
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| column | int | Excel 列索引 |
|
||||||
|
| attributes | dict[str, str] | 信号属性字典,键为行号,值为单元格值 |
|
||||||
|
| datalog | list[DataLog] | 数据日志列表 |
|
||||||
|
|
||||||
|
**方法说明**:
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 说明 |
|
||||||
|
|------|--------|------|
|
||||||
|
| to_dict() | dict[str, Any] | 转换为字典格式 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
signal = SignalData(column=2, attributes={"type": "boolean"}, datalog=[DataLog(0.0, "off")])
|
||||||
|
data = signal.to_dict()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ExcelDataResult
|
||||||
|
|
||||||
|
Excel 数据读取结果封装,提供对 Excel 数据的类型安全访问。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class ExcelDataResult:
|
||||||
|
sheet_name: str = "Scenario1" # 工作表名称
|
||||||
|
source_row: int = 0 # Source: Input 所在行号
|
||||||
|
signals: dict[str, SignalData] = field(default_factory=dict) # 信号字典
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性说明**:
|
||||||
|
|
||||||
|
| 属性 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| sheet_name | str | 工作表名称,默认 "Scenario1" |
|
||||||
|
| source_row | int | "Source: Input" 标记所在行号 |
|
||||||
|
| signals | dict[str, SignalData] | 信号名称到信号数据的映射 |
|
||||||
|
|
||||||
|
**方法说明**:
|
||||||
|
|
||||||
|
| 方法 | 参数 | 返回值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| get_signal() | name: str | SignalData \| None | 获取指定信号的数据 |
|
||||||
|
| get_signal_names() | - | list[str] | 获取所有信号名称 |
|
||||||
|
| to_dict() | - | dict[str, Any] | 转换为字典格式 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
result = ExcelDataResult(sheet_name="Scenario1", source_row=3, signals={})
|
||||||
|
signal = result.get_signal("signal_name")
|
||||||
|
names = result.get_signal_names()
|
||||||
|
data = result.to_dict()
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ExcelReaderConfig
|
||||||
|
|
||||||
|
Excel 读取配置类,用于配置 Excel 文件的解析规则。
|
||||||
|
|
||||||
|
```python
|
||||||
|
@dataclass
|
||||||
|
class ExcelReaderConfig:
|
||||||
|
sheet_name: str = "Scenario1" # 工作表名称
|
||||||
|
source_header: str = "Source: Input" # 数据源标记行文本
|
||||||
|
time_column: int = 1 # 时间列索引(A 列)
|
||||||
|
header_row: int = 1 # 信号名称所在行号
|
||||||
|
type_row: int = 3 # 信号类型所在行号
|
||||||
|
interp_row: int = 6 # 插值类型所在行号
|
||||||
|
data_start_row_offset: int = 1 # 数据起始行偏移量
|
||||||
|
output_header: str = "Source: Output" # 输出标记行文本
|
||||||
|
block_path_row: int = 4 # 块路径所在行号
|
||||||
|
```
|
||||||
|
|
||||||
|
**属性说明**:
|
||||||
|
|
||||||
|
| 属性 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| sheet_name | str | "Scenario1" | 工作表名称 |
|
||||||
|
| source_header | str | "Source: Input" | 数据源标记行文本 |
|
||||||
|
| time_column | int | 1 | 时间列索引(A 列) |
|
||||||
|
| header_row | int | 1 | 信号名称所在行号 |
|
||||||
|
| type_row | int | 3 | 信号类型所在行号 |
|
||||||
|
| interp_row | int | 6 | 插值类型所在行号 |
|
||||||
|
| data_start_row_offset | int | 1 | 相对于 source_row 的数据起始行偏移量 |
|
||||||
|
| output_header | str | "Source: Output" | 输出标记行文本 |
|
||||||
|
| block_path_row | int | 4 | 块路径所在行号 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
config = ExcelReaderConfig(
|
||||||
|
sheet_name="Scenario1",
|
||||||
|
source_header="Source: Input",
|
||||||
|
time_column=1
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 异常体系
|
||||||
|
|
||||||
|
异常模块位于 [exceptions.py](file:///f:/MyProject/mil_sdk/src/core/exceptions.py)。
|
||||||
|
|
||||||
|
### 异常层次
|
||||||
|
|
||||||
|
```
|
||||||
|
Exception
|
||||||
|
└── MILSDKError (基础异常)
|
||||||
|
├── ExcelReadError (文件读取错误)
|
||||||
|
├── ExcelFormatError (格式错误)
|
||||||
|
├── CaseDataError (用例数据错误)
|
||||||
|
└── ExcelWriteError (文件写入错误)
|
||||||
|
```
|
||||||
|
|
||||||
|
### MILSDKError
|
||||||
|
|
||||||
|
基础异常类,所有 SDK 自定义异常的基类。
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MILSDKError(Exception):
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### ExcelReadError
|
||||||
|
|
||||||
|
Excel 文件读取错误,当文件不存在或读取失败时抛出。
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExcelReadError(MILSDKError):
|
||||||
|
"""Excel 文件读取错误(文件不存在、权限问题等)"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**触发场景**:
|
||||||
|
- 文件不存在
|
||||||
|
- 文件权限问题
|
||||||
|
- 文件格式损坏
|
||||||
|
|
||||||
|
### ExcelFormatError
|
||||||
|
|
||||||
|
Excel 格式错误,当 Excel 格式不符合预期时抛出。
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExcelFormatError(MILSDKError):
|
||||||
|
"""Excel 格式错误(缺少 Sheet、格式不匹配等)"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**触发场景**:
|
||||||
|
- 缺少指定的 Sheet
|
||||||
|
- 缺少 "Source: Input" 标记
|
||||||
|
- 缺少模板版本号
|
||||||
|
|
||||||
|
### CaseDataError
|
||||||
|
|
||||||
|
用例数据错误,当用例数据异常时抛出。
|
||||||
|
|
||||||
|
```python
|
||||||
|
class CaseDataError(MILSDKError):
|
||||||
|
"""用例数据错误(信号不存在、类型错误等)"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**触发场景**:
|
||||||
|
- 信号名称不存在
|
||||||
|
- 时间格式错误
|
||||||
|
- 缺少用例标题
|
||||||
|
|
||||||
|
### ExcelWriteError
|
||||||
|
|
||||||
|
Excel 文件写入错误,当文件写入失败时抛出。
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ExcelWriteError(MILSDKError):
|
||||||
|
"""Excel 文件写入错误(权限问题、保存失败等)"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
**触发场景**:
|
||||||
|
- 文件权限问题
|
||||||
|
- 磁盘空间不足
|
||||||
|
- 保存失败
|
||||||
|
|
||||||
|
**异常处理示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import (
|
||||||
|
MILSDKError,
|
||||||
|
ExcelReadError,
|
||||||
|
ExcelFormatError,
|
||||||
|
CaseDataError,
|
||||||
|
ExcelWriteError,
|
||||||
|
read_excel_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = read_excel_data("data.xlsx")
|
||||||
|
except ExcelReadError as e:
|
||||||
|
print(f"文件读取失败: {e}")
|
||||||
|
except ExcelFormatError as e:
|
||||||
|
print(f"格式错误: {e}")
|
||||||
|
except MILSDKError as e:
|
||||||
|
print(f"SDK 错误: {e}")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 日志模块
|
||||||
|
|
||||||
|
日志模块位于 [logging_config.py](file:///f:/MyProject/mil_sdk/src/core/logging_config.py)。
|
||||||
|
|
||||||
|
### setup_logging
|
||||||
|
|
||||||
|
配置日志系统,设置日志级别、输出目标等。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def setup_logging(
|
||||||
|
level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO",
|
||||||
|
log_file: str | Path | None = "logs/mil_sdk.log",
|
||||||
|
console_output: bool = True,
|
||||||
|
) -> logging.Logger
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数说明**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| level | str | "INFO" | 日志级别,可选 "DEBUG"、"INFO"、"WARNING"、"ERROR" |
|
||||||
|
| log_file | str \| Path \| None | "logs/mil_sdk.log" | 日志文件路径,设为 None 则不写入文件 |
|
||||||
|
| console_output | bool | True | 是否输出到控制台 |
|
||||||
|
|
||||||
|
**返回值**:根日志记录器 (logging.Logger)
|
||||||
|
|
||||||
|
**日志格式**:`%(asctime)s [%(levelname)s] %(message)s`
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import setup_logging
|
||||||
|
|
||||||
|
logger = setup_logging(level="DEBUG", log_file="logs/mil_sdk.log")
|
||||||
|
```
|
||||||
|
|
||||||
|
### get_logger
|
||||||
|
|
||||||
|
获取指定名称的日志记录器。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_logger(name: str) -> logging.Logger
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数说明**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| name | str | 日志记录器名称,通常使用 `__name__` |
|
||||||
|
|
||||||
|
**返回值**:日志记录器实例
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
logger.info("This is an info message")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Excel 读取模块
|
||||||
|
|
||||||
|
### read_excel_data
|
||||||
|
|
||||||
|
读取 MIL 仿真 Excel 文件并解析信号数据。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def read_excel_data(
|
||||||
|
excel_path: str,
|
||||||
|
return_object: bool = False,
|
||||||
|
config: ExcelReaderConfig | None = None
|
||||||
|
) -> DataDict | ExcelDataResult
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数说明**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| excel_path | str | - | Excel 文件路径 |
|
||||||
|
| return_object | bool | False | 是否返回 ExcelDataResult 对象(推荐),False 保持向后兼容 |
|
||||||
|
| config | ExcelReaderConfig \| None | None | Excel 读取配置,默认使用 ExcelReaderConfig() |
|
||||||
|
|
||||||
|
**返回值**:
|
||||||
|
|
||||||
|
`return_object=False` 时返回包含以下键的字典(向后兼容):
|
||||||
|
- `wb`: Workbook 对象
|
||||||
|
- `sheet`: Worksheet 对象
|
||||||
|
- `source_row`: Source: Input 所在行号
|
||||||
|
- `<信号名>`: 信号元数据(type, column, datalog)
|
||||||
|
|
||||||
|
`return_object=True` 时返回 ExcelDataResult 对象(推荐):
|
||||||
|
- `sheet_name`: 工作表名称
|
||||||
|
- `source_row`: Source: Input 所在行号
|
||||||
|
- `signals`: 信号名称到信号数据的映射
|
||||||
|
|
||||||
|
**异常**:
|
||||||
|
|
||||||
|
| 异常类型 | 触发条件 |
|
||||||
|
|----------|----------|
|
||||||
|
| ExcelReadError | 文件不存在或读取失败 |
|
||||||
|
| ExcelFormatError | Excel 格式不符合预期 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import read_excel_data
|
||||||
|
|
||||||
|
# 使用推荐的方式
|
||||||
|
result = read_excel_data("simulation.xlsx", return_object=True)
|
||||||
|
for name in result.get_signal_names():
|
||||||
|
signal = result.get_signal(name)
|
||||||
|
if signal:
|
||||||
|
print(f"信号: {name}, 数据点: {len(signal.datalog)}")
|
||||||
|
|
||||||
|
# 使用向后兼容的方式
|
||||||
|
data = read_excel_data("simulation.xlsx")
|
||||||
|
wb = data["wb"]
|
||||||
|
sheet = data["sheet"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### read_excel_case
|
||||||
|
|
||||||
|
读取 Excel 用例模板。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def read_excel_case(
|
||||||
|
excel_path: str,
|
||||||
|
data_dict: dict,
|
||||||
|
addTimeEn: bool,
|
||||||
|
) -> CaseDict
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数说明**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| excel_path | str | Excel 模板文件路径 |
|
||||||
|
| data_dict | dict | 信号数据字典 |
|
||||||
|
| addTimeEn | bool | 是否累加时间 |
|
||||||
|
|
||||||
|
**返回值**:用例字典
|
||||||
|
|
||||||
|
**异常**:
|
||||||
|
|
||||||
|
| 异常类型 | 触发条件 |
|
||||||
|
|----------|----------|
|
||||||
|
| ExcelReadError | 文件读取失败 |
|
||||||
|
| ExcelFormatError | 格式错误 |
|
||||||
|
| CaseDataError | 用例数据错误 |
|
||||||
|
|
||||||
|
**用例字典结构**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"Sheet名称": {
|
||||||
|
"用例标题": {
|
||||||
|
"enable": bool, # 是否启用
|
||||||
|
"step": {
|
||||||
|
"step0": {
|
||||||
|
"name": str, # 步骤名称
|
||||||
|
"time": float, # 时间
|
||||||
|
"action": dict # 操作字典
|
||||||
|
},
|
||||||
|
"step1": {...}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import read_excel_case, read_excel_data
|
||||||
|
|
||||||
|
data_dict = read_excel_data("simulation.xlsx", return_object=False)
|
||||||
|
cases = read_excel_case("template.xlsx", data_dict, addTimeEn=True)
|
||||||
|
|
||||||
|
for sheet_name, sheet_cases in cases.items():
|
||||||
|
print(f"Sheet: {sheet_name}")
|
||||||
|
for case_name, case_data in sheet_cases.items():
|
||||||
|
print(f" 用例: {case_name}, 启用: {case_data['enable']}")
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Excel 生成模块
|
||||||
|
|
||||||
|
### create_excel_case
|
||||||
|
|
||||||
|
根据数据和用例模板生成测试用例 Excel 文件。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def create_excel_case(
|
||||||
|
excel_path: str,
|
||||||
|
data_dict: dict,
|
||||||
|
sheets_dict: dict,
|
||||||
|
) -> None
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数说明**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| excel_path | str | 输出目录路径 |
|
||||||
|
| data_dict | dict | 数据字典 |
|
||||||
|
| sheets_dict | dict | 工作表字典 |
|
||||||
|
|
||||||
|
**异常**:
|
||||||
|
|
||||||
|
| 异常类型 | 触发条件 |
|
||||||
|
|----------|----------|
|
||||||
|
| CaseDataError | 数据异常 |
|
||||||
|
| ExcelWriteError | 文件写入错误 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import read_excel_data, read_excel_case, create_excel_case
|
||||||
|
|
||||||
|
data_dict = read_excel_data("simulation.xlsx", return_object=False)
|
||||||
|
sheets_dict = read_excel_case("template.xlsx", data_dict, addTimeEn=True)
|
||||||
|
create_excel_case("output/", data_dict, sheets_dict)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Excel 更新模块
|
||||||
|
|
||||||
|
### update_case_excel
|
||||||
|
|
||||||
|
比较新旧数据差异,更新 Excel 文件中的信号列。
|
||||||
|
|
||||||
|
```python
|
||||||
|
def update_case_excel(
|
||||||
|
filename: str,
|
||||||
|
old_data: dict,
|
||||||
|
new_data: dict,
|
||||||
|
) -> None
|
||||||
|
```
|
||||||
|
|
||||||
|
**参数说明**:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| filename | str | Excel 文件路径 |
|
||||||
|
| old_data | dict | 旧数据字典 |
|
||||||
|
| new_data | dict | 新数据字典 |
|
||||||
|
|
||||||
|
**功能说明**:
|
||||||
|
- 比较新旧数据中的信号差异
|
||||||
|
- 在旧文件中添加新数据独有的信号列
|
||||||
|
- 从旧文件中删除新数据不存在的信号列
|
||||||
|
|
||||||
|
**异常**:
|
||||||
|
|
||||||
|
| 异常类型 | 触发条件 |
|
||||||
|
|----------|----------|
|
||||||
|
| CaseDataError | 数据类型错误 |
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import read_excel_data, update_case_excel
|
||||||
|
|
||||||
|
new_data = read_excel_data("new_data.xlsx", return_object=False)
|
||||||
|
old_data = read_excel_data("old_data.xlsx", return_object=False)
|
||||||
|
update_case_excel("updated.xlsx", old_data, new_data)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API 参考
|
||||||
|
|
||||||
|
### 公共导入
|
||||||
|
|
||||||
|
所有公共 API 均可通过以下方式导入:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import (
|
||||||
|
# 数据模型
|
||||||
|
DataLog,
|
||||||
|
SignalData,
|
||||||
|
ExcelDataResult,
|
||||||
|
ExcelReaderConfig,
|
||||||
|
# 核心函数
|
||||||
|
read_excel_data,
|
||||||
|
read_excel_case,
|
||||||
|
create_excel_case,
|
||||||
|
update_case_excel,
|
||||||
|
# 异常
|
||||||
|
MILSDKError,
|
||||||
|
ExcelReadError,
|
||||||
|
ExcelFormatError,
|
||||||
|
CaseDataError,
|
||||||
|
ExcelWriteError,
|
||||||
|
# 日志
|
||||||
|
setup_logging,
|
||||||
|
get_logger,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 函数签名汇总
|
||||||
|
|
||||||
|
| 函数 | 签名 |
|
||||||
|
|------|------|
|
||||||
|
| DataLog | `DataLog(time: float = 0.0, value: str = "")` |
|
||||||
|
| SignalData | `SignalData(column: int = 0, attributes: dict = {}, datalog: list = [])` |
|
||||||
|
| ExcelDataResult | `ExcelDataResult(sheet_name: str = "Scenario1", source_row: int = 0, signals: dict = {})` |
|
||||||
|
| ExcelReaderConfig | `ExcelReaderConfig(...)` |
|
||||||
|
| read_excel_data | `read_excel_data(excel_path: str, return_object: bool = False, config: ExcelReaderConfig \| None = None) -> DataDict \| ExcelDataResult` |
|
||||||
|
| read_excel_case | `read_excel_case(excel_path: str, data_dict: dict, addTimeEn: bool) -> CaseDict` |
|
||||||
|
| create_excel_case | `create_excel_case(excel_path: str, data_dict: dict, sheets_dict: dict) -> None` |
|
||||||
|
| update_case_excel | `update_case_excel(filename: str, old_data: dict, new_data: dict) -> None` |
|
||||||
|
| setup_logging | `setup_logging(level: str = "INFO", log_file: str \| Path \| None = "logs/mil_sdk.log", console_output: bool = True) -> logging.Logger` |
|
||||||
|
| get_logger | `get_logger(name: str) -> logging.Logger` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
### 基础用法
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import setup_logging, read_excel_data
|
||||||
|
|
||||||
|
setup_logging()
|
||||||
|
result = read_excel_data("simulation.xlsx", return_object=True)
|
||||||
|
|
||||||
|
signal_names = result.get_signal_names()
|
||||||
|
print(f"共解析 {len(signal_names)} 个信号")
|
||||||
|
|
||||||
|
for name in signal_names:
|
||||||
|
signal = result.get_signal(name)
|
||||||
|
if signal:
|
||||||
|
print(f" {name}: {len(signal.datalog)} 个数据点")
|
||||||
|
```
|
||||||
|
|
||||||
|
### 完整工作流
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pathlib import Path
|
||||||
|
from src.core import (
|
||||||
|
setup_logging,
|
||||||
|
read_excel_data,
|
||||||
|
read_excel_case,
|
||||||
|
create_excel_case,
|
||||||
|
update_case_excel,
|
||||||
|
)
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
setup_logging(level="INFO")
|
||||||
|
|
||||||
|
excel_path = Path(__file__).parent
|
||||||
|
|
||||||
|
data_dict = read_excel_data("new_data.xlsx", return_object=False)
|
||||||
|
old_data_dict = read_excel_data("old_data.xlsx", return_object=False)
|
||||||
|
|
||||||
|
update_case_excel("new_case.xlsx", old_data_dict, data_dict)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误处理
|
||||||
|
|
||||||
|
```python
|
||||||
|
from src.core import (
|
||||||
|
ExcelReadError,
|
||||||
|
ExcelFormatError,
|
||||||
|
CaseDataError,
|
||||||
|
MILSDKError,
|
||||||
|
read_excel_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = read_excel_data("simulation.xlsx", return_object=True)
|
||||||
|
except ExcelReadError as e:
|
||||||
|
print(f"文件读取失败: {e}")
|
||||||
|
raise
|
||||||
|
except ExcelFormatError as e:
|
||||||
|
print(f"格式错误: {e}")
|
||||||
|
raise
|
||||||
|
except MILSDKError as e:
|
||||||
|
print(f"SDK 错误: {e}")
|
||||||
|
raise
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Excel 文件格式约定
|
||||||
|
|
||||||
|
### 仿真数据文件格式
|
||||||
|
|
||||||
|
Excel 仿真数据文件遵循以下格式约定:
|
||||||
|
|
||||||
|
| 行号 | 内容 |
|
||||||
|
|------|------|
|
||||||
|
| 1 | 信号名称(time, signal1, signal2...) |
|
||||||
|
| 2 | 预留行(通常为空) |
|
||||||
|
| 3 | "Source: Input" 标记行,标识数据列开始 |
|
||||||
|
| 4 | 信号类型信息 |
|
||||||
|
| 5 | 块路径信息 |
|
||||||
|
| 6 | 插值类型信息 |
|
||||||
|
| 7+ | 时间-值数据对 |
|
||||||
|
|
||||||
|
**示例结构**:
|
||||||
|
|
||||||
|
| A | B | C | D |
|
||||||
|
|---|---|---|---|
|
||||||
|
| time | signal1 | signal2 | signal3 |
|
||||||
|
| | | | |
|
||||||
|
| Source: Input | Source: Input | Source: Input | Source: Input |
|
||||||
|
| type | boolean | float | boolean |
|
||||||
|
| BlockPath | /model/signal1 | /model/signal2 | /model/signal3 |
|
||||||
|
| Interp | const | linear | zero-order hold |
|
||||||
|
| | off | 0.0 | true |
|
||||||
|
| 1.0 | on | 1.5 | false |
|
||||||
|
| 2.0 | off | 2.0 | true |
|
||||||
|
|
||||||
|
**要求**:
|
||||||
|
- Sheet 名称:`Scenario1`
|
||||||
|
- 时间列:必须存在且列名为 "time"
|
||||||
|
- 跳过列:列名为 "Parameter:"、"Value"、"BlockPath" 的列会被跳过
|
||||||
|
|
||||||
|
### 用例模板文件格式
|
||||||
|
|
||||||
|
用例模板 Excel 文件遵循以下格式约定:
|
||||||
|
|
||||||
|
| Sheet 名称 | 内容 |
|
||||||
|
|-----------|------|
|
||||||
|
| Atech-Hefei | 模板版本号 |
|
||||||
|
| 其他 Sheet | 测试用例数据 |
|
||||||
|
|
||||||
|
**用例数据格式**:
|
||||||
|
|
||||||
|
| 列号 | 列名 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 1 | TITLE | 用例标题 |
|
||||||
|
| 2 | STATUS | 状态(完成测试/未完成) |
|
||||||
|
| 3 | ACTION | 操作描述(signal1=value1; signal2=value2) |
|
||||||
|
| 4 | NAME | 步骤名称 |
|
||||||
|
| 5 | TIME | 时间 |
|
||||||
|
|
||||||
|
**操作字符串格式**:
|
||||||
|
- 多条操作使用分号 `;` 分隔
|
||||||
|
- 操作格式:`信号名=值`
|
||||||
|
- 示例:`signal1=on; signal2=0.5`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本历史
|
||||||
|
|
||||||
|
### v0.1.0 (当前版本)
|
||||||
|
|
||||||
|
- 初始版本发布
|
||||||
|
- 支持 Excel 数据文件读取和解析
|
||||||
|
- 支持测试用例模板读取和生成
|
||||||
|
- 支持新旧数据对比和更新
|
||||||
Reference in New Issue
Block a user