# 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 #include // 定义结构体 (需与上述定义一致) 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`。