Files
RL_Engine_Control/engine_env/DLL_Usage_Guide.md
T

228 lines
7.8 KiB
Markdown
Raw Normal View History

2025-12-30 19:10:49 +08:00
# libEngine.dll 调用指南
本文档详细说明了如何通过 C++ 和 Python 调用 `libEngine.dll` 进行发动机仿真。
## 1. 数据结构定义
无论使用哪种语言,都需要严格遵循以下数据结构定义(内存布局)。
### 1.1 Engine_Identity (身份/配置参数)
| 字段名 | 类型 (C++) | 类型 (Python ctypes) | 说明 |
| :------------------------ | :--------- | :------------------- | :------------------------- |
| `Identity_Ok` | `int` | `c_int` | 身份验证位,通常设为 1 |
| `Cof_Eff_Low_Identity` | `double` | `c_double` | 低压部件效率系数,默认 1.0 |
| `Cof_Eff_High_Identity` | `double` | `c_double` | 高压部件效率系数,默认 1.0 |
### 1.2 EngInPut (输入控制量)
| 字段名 | 类型 (C++) | 类型 (Python ctypes) | 说明 |
| :----------------- | :--------- | :------------------- | :--------------------- |
| `Altp` | `double` | `c_double` | 飞行高度 (m) |
| `Ma0` | `double` | `c_double` | 飞行马赫数 |
| `dT0` | `double` | `c_double` | 与标准大气温差 (K) |
| `StepTime` | `double` | `c_double` | 仿真步长 (s) |
| `Wf` | `double` | `c_double` | 主燃烧室供油量 (kg/h) |
| `Wf_After` | `double` | `c_double` | 加力供油量 (kg/h) |
| `Angle_FanVane` | `double` | `c_double` | 风扇导流叶片角度 |
| `Angle_CompVane` | `double` | `c_double` | 高压压气机导流叶片角度 |
| `A8` | `double` | `c_double` | 喷口临界面积 (m^2) |
| `AddPower` | `double` | `c_double` | 附加功率/起动功率 (W) |
### 1.3 EngOutPut (输出状态量)
| 字段名 | 类型 (C++) | 类型 (Python ctypes) | 说明 |
| :---------- | :--------- | :------------------- | :-------------------------- |
| `NL` | `double` | `c_double` | 风扇相对转速 (%) |
| `NH` | `double` | `c_double` | 高压相对转速 (%) |
| `T1t` | `double` | `c_double` | 进气温度 (K) |
| `P1t` | `double` | `c_double` | 进气总压 (kPa) |
| `P1s` | `double` | `c_double` | 风扇进口静压 (kPa) |
| `P3s` | `double` | `c_double` | 高压压气机后静压 (kPa) |
| `T5t` | `double` | `c_double` | 涡轮后温度 (K) |
| `P5t` | `double` | `c_double` | 涡轮后压力 (kPa) |
| `Wf_Main` | `double` | `c_double` | 实际燃烧主燃油流量 (kg/h) |
| `T5t_Gas` | `double` | `c_double` | 涡轮后气体温度 (无惯性) (K) |
---
## 2. C++ 调用方法
在 C++ 中,通常使用 `LoadLibrary``GetProcAddress` 进行显式调用(动态加载)。
### 函数原型
```cpp
// 假设使用 stdcall 调用约定
typedef struct EngOutPut (__stdcall *CreateEngFunc)(int **pEngine, struct Engine_Identity m_Identity);
typedef struct EngOutPut (__stdcall *EngStepGoFunc)(int *pEngine, struct EngInPut m_EngInPut);
typedef struct EngOutPut (__stdcall *DestroyEngFunc)(int *pEngine);
```
### 示例代码
```cpp
#include <windows.h>
#include <iostream>
// 定义结构体 (需与上述定义一致)
struct Engine_Identity {
int Identity_Ok;
double Cof_Eff_Low_Identity;
double Cof_Eff_High_Identity;
};
struct EngInPut {
double Altp, Ma0, dT0, StepTime;
double Wf, Wf_After, Angle_FanVane, Angle_CompVane, A8, AddPower;
};
struct EngOutPut {
double NL, NH, T1t, P1t, P1s, P3s, T5t, P5t, Wf_Main, T5t_Gas;
};
// 定义函数指针类型
typedef EngOutPut (__stdcall *CreateEngFunc)(int**, Engine_Identity);
typedef EngOutPut (__stdcall *EngStepGoFunc)(int*, EngInPut);
typedef EngOutPut (__stdcall *DestroyEngFunc)(int*);
int main() {
// 1. 加载 DLL
HMODULE hDll = LoadLibrary("libEngine.dll");
if (!hDll) {
std::cerr << "无法加载 DLL" << std::endl;
return 1;
}
// 2. 获取函数地址
CreateEngFunc CreateEng = (CreateEngFunc)GetProcAddress(hDll, "CreateEng");
EngStepGoFunc EngStepGo = (EngStepGoFunc)GetProcAddress(hDll, "EngStepGo");
DestroyEngFunc DestroyEng = (DestroyEngFunc)GetProcAddress(hDll, "DestroyEng");
if (!CreateEng || !EngStepGo || !DestroyEng) {
std::cerr << "无法获取函数地址" << std::endl;
FreeLibrary(hDll);
return 1;
}
// 3. 创建发动机实例
int* hEngine = nullptr; // 句柄指针
Engine_Identity identity = {1, 1.0, 1.0};
// 注意:CreateEng 需要传入指针的地址 (&hEngine)
CreateEng(&hEngine, identity);
if (!hEngine) {
std::cerr << "发动机创建失败" << std::endl;
FreeLibrary(hDll);
return 1;
}
// 4. 仿真循环
EngInPut input = {0};
input.StepTime = 0.02;
input.Wf = 100.0;
input.A8 = 0.1;
input.AddPower = 90000.0; // 起动功率
for (int i = 0; i < 100; ++i) {
// 执行单步
EngOutPut output = EngStepGo(hEngine, input);
std::cout << "Step: " << i
<< " NH: " << output.NH
<< " T5t: " << output.T5t << std::endl;
// 简单的起动逻辑示例
if (output.NH > 0.25) {
input.AddPower = 0.0;
input.Wf = 300.0;
}
}
// 5. 销毁与释放
DestroyEng(hEngine);
FreeLibrary(hDll);
return 0;
}
```
---
## 3. Python 调用方法
Python 中推荐使用 `ctypes` 库进行调用。
### 核心要点
1. 使用 `ctypes.Structure` 定义对应的 C 结构体。
2. 使用 `WinDLL` 加载 DLL(因为是 `__stdcall` 调用约定)。
3. 配置 `argtypes``restype` 以确保参数传递正确。
### 示例代码 (基于封装好的类)
```python
import ctypes
from ctypes import *
import os
# --- 结构体定义 (略,见 core_model.py) ---
class EngineSim:
def __init__(self, dll_path):
self.lib = WinDLL(dll_path)
# 配置函数原型
# CreateEng: 传入 int** (POINTER(POINTER(c_int)))
self.lib.CreateEng.argtypes = [POINTER(POINTER(c_int)), Engine_Identity]
self.lib.CreateEng.restype = EngOutPut
# EngStepGo: 传入 int* (POINTER(c_int))
self.lib.EngStepGo.argtypes = [POINTER(c_int), EngInPut]
self.lib.EngStepGo.restype = EngOutPut
# DestroyEng: 传入 int*
self.lib.DestroyEng.argtypes = [POINTER(c_int)]
self.lib.DestroyEng.restype = EngOutPut
self.h_engine = None
def create(self):
self.h_engine = POINTER(c_int)() # 创建一个空指针用于接收句柄
identity = Engine_Identity(1, 1.0, 1.0)
# 传入指针的引用 byref
self.lib.CreateEng(byref(self.h_engine), identity)
def step(self, input_data):
return self.lib.EngStepGo(self.h_engine, input_data)
def close(self):
if self.h_engine:
self.lib.DestroyEng(self.h_engine)
self.h_engine = None
# --- 使用 ---
if __name__ == "__main__":
dll_path = os.path.join(os.path.dirname(__file__), "libEngine.dll")
sim = EngineSim(dll_path)
sim.create()
inp = EngInPut()
inp.StepTime = 0.02
inp.Wf = 100.0
inp.AddPower = 90000.0
inp.A8 = 0.1
for i in range(100):
out = sim.step(inp)
print(f"NH: {out.NH:.2f}, T5t: {out.T5t:.2f}")
sim.close()
```
### 注意事项
* **指针传递**: `CreateEng` 在 C++ 中接收 `int**`,在 Python `ctypes` 中对应 `byref(h_engine)`,其中 `h_engine``POINTER(c_int)()`
* **调用约定**: 必须使用 `WinDLL` 而不是 `CDLL`,除非 DLL 编译时使用的是 `cdecl`。根据现有代码推断为 `stdcall`