7.8 KiB
7.8 KiB
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 进行显式调用(动态加载)。
函数原型
// 假设使用 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);
示例代码
#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 库进行调用。
核心要点
- 使用
ctypes.Structure定义对应的 C 结构体。 - 使用
WinDLL加载 DLL(因为是__stdcall调用约定)。 - 配置
argtypes和restype以确保参数传递正确。
示例代码 (基于封装好的类)
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**,在 Pythonctypes中对应byref(h_engine),其中h_engine是POINTER(c_int)()。 - 调用约定: 必须使用
WinDLL而不是CDLL,除非 DLL 编译时使用的是cdecl。根据现有代码推断为stdcall。