本文的背景是,我用python写了一份算法的的代码,希望提供给他人使用,但是我又不希望他能看到我的源码,我希望提供给他相应的接口,他可以调用该接口,输入参数,拿到对应的输出参数即可。这样即可以让他使用这份算法,又保护了我们自己的源码。
本文操作的过程是基于Ubuntu24.04完成的。
下面记录一下完整的部署方案
1 创建完整的项目结构
首先需要重构代码结构,使其更适合编译;
完整的项目结构如下所示:
pump_energy_optimizer/
├── pump_optimizer.pyx # 算法脚本
├── setup.py # 编译脚本
├── usage_example.py # 使用示例
├── requirements.txt # 依赖列表
└── README.md # 说明文档
2 编写核心代码文件
创建一个新的 .pyx 文件(例如 pump_optimizer.pyx)并将原始 Python 代码移入这个文件。其实就是将原来的算法py文件复制一份,后缀改成pyx
import math
import copy
class PumpEnergyOptimizer:
def __init__(self, pipe_resistance=1.0, dynamic_head=1.0,
high_level_alarm=7.0, low_level_alarm=1.0):
"""
初始化水泵能量优化器
Args:
pipe_resistance: 管阻 (米)
dynamic_head: 动扬程 (米)
high_level_alarm: 高液位报警值 (米)
low_level_alarm: 低液位报警值 (米)
"""
self.last_level = None
self.high_level_alarm = high_level_alarm
self.low_level_alarm = low_level_alarm
self.pipe_resistance = pipe_resistance
self.dynamic_head = dynamic_head
# 标准水泵数据
self.standard_pump_data = {
14: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37],
'flow': [987, 917, 846, 776, 705, 635, 573, 515, 461, 406, 350, 298, 240, 170],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21]
},
13: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35],
'flow': [1075, 1009, 940, 870, 799, 727, 657, 590, 530, 473, 420, 360, 310, 255, 190, 100],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18]
},
12: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34],
'flow': [1154, 1093, 1030, 962, 894, 823, 752, 680, 610, 550, 487, 434, 380, 325, 268, 210, 140],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16]
},
11: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33],
'flow': [1228, 1171, 1113, 1052, 989, 921, 854, 784, 712, 641, 572, 508, 450, 397, 340, 285, 230, 170],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15]
},
10: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32],
'flow': [1300, 1245, 1189, 1133, 1075, 1015, 952, 886, 818, 746, 676, 605, 535, 473, 415, 360, 310, 256, 195],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14]
},
9: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31],
'flow': [1370, 1320, 1264, 1209, 1154, 1098, 1041, 981, 919, 850, 785, 712, 640, 570, 505, 443, 387, 330, 272, 225],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14, 13]
},
8: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31],
'flow': [1458, 1400, 1340, 1285, 1230, 1178, 1123, 1067, 1011, 953, 890, 828, 762, 692, 620, 549, 480, 417, 362, 300],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14, 13]
},
7: {
'freq': [50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31],
'flow': [1620, 1537, 1445, 1375, 1320, 1260, 1200, 1152, 1097, 1040, 980, 930, 870, 808, 743, 675, 604, 532, 462, 398],
'power': [58, 55, 52, 48, 45, 42, 40, 37, 34, 31, 29, 27, 23, 21, 19, 18, 16, 15, 14, 13]
}
}
# 当前使用的水泵数据(可能经过调整)
self.current_pump_data = copy.deepcopy(self.standard_pump_data)
def set_pump_parameters(self, pipe_resistance=None, dynamic_head=None,
high_level_alarm=None, low_level_alarm=None):
"""
设置水泵参数
Args:
pipe_resistance: 管阻 (米)
dynamic_head: 动扬程 (米)
high_level_alarm: 高液位报警值 (米)
low_level_alarm: 低液位报警值 (米)
"""
if pipe_resistance is not None:
self.pipe_resistance = pipe_resistance
if dynamic_head is not None:
self.dynamic_head = dynamic_head
if high_level_alarm is not None:
self.high_level_alarm = high_level_alarm
if low_level_alarm is not None:
self.low_level_alarm = low_level_alarm
return True
def set_level_alarm(self, high_level_alarm, low_level_alarm):
"""
设置液位报警值
Args:
high_level_alarm: 高液位报警值 (米)
low_level_alarm: 低液位报警值 (米)
"""
self.high_level_alarm = high_level_alarm
self.low_level_alarm = low_level_alarm
return True
def adjust_pump_data(self, head_to_adjust, flow_factor=1.0, power_factor=1.0, freq_factor=1.0):
"""
调整特定扬程的水泵数据
Args:
head_to_adjust: 需要调整的扬程值 (7-14)
flow_factor: 标准流量动态系数 (0-2)
power_factor: 标准功率动态系数 (0-2)
freq_factor: 输出频率动态系数 (0-2)
"""
if head_to_adjust not in self.current_pump_data:
raise ValueError(f"扬程 {head_to_adjust} 不在数据范围内 (7-14m)")
# 应用调整系数
data = self.current_pump_data[head_to_adjust]
# 调整流量
data['flow'] = [flow * flow_factor for flow in data['flow']]
# 调整功率
data['power'] = [power * power_factor for power in data['power']]
# 调整频率
data['freq'] = [freq * freq_factor for freq in data['freq']]
return True
def reset_pump_data(self):
"""重置水泵数据为标准数据"""
self.current_pump_data = copy.deepcopy(self.standard_pump_data)
return True
def calculate_total_head(self, current_level):
"""计算总扬程"""
# 总扬程 = 5m + 8m - 液位值 + 动扬程 + 管阻
h_total = 5 + 8 - current_level + self.dynamic_head + self.pipe_resistance
return math.ceil(h_total) # 向上取整
def interpolate_frequency_power(self, target_flow, head):
"""根据目标流量插值计算频率和功率"""
if head not in self.current_pump_data:
raise ValueError(f"扬程 {head}m 不在数据范围内")
data = self.current_pump_data[head]
flow_list = data['flow']
freq_list = data['freq']
power_list = data['power']
# 由于流量列表是递减的,需要调整边界检查逻辑
if target_flow >= flow_list[0]:
return freq_list[0], power_list[0]
if target_flow <= flow_list[-1]:
return freq_list[-1], power_list[-1]
# 查找流量所在区间(注意:流量是递减的)
for i in range(1, len(flow_list)):
if target_flow >= flow_list[i]:
# 线性插值
flow_high, flow_low = flow_list[i-1], flow_list[i]
freq_high, freq_low = freq_list[i-1], freq_list[i]
power_high, power_low = power_list[i-1], power_list[i]
fraction = (target_flow - flow_low) / (flow_high - flow_low)
freq = freq_low + fraction * (freq_high - freq_low)
power = power_low + fraction * (power_high - power_low)
return round(freq, 2), round(power, 2)
return freq_list[-1], power_list[-1]
def check_level_alarm(self, current_level):
"""检查液位报警"""
alarms = []
if current_level >= self.high_level_alarm:
alarms.append(f"高液位报警!当前液位: {current_level}m")
if current_level <= self.low_level_alarm:
alarms.append(f"低液位报警!当前液位: {current_level}m")
return alarms
def should_recalculate(self, current_level):
"""判断是否需要重新计算"""
if self.last_level is None:
return True
return True # 每次都重新计算
def optimize_pump_operation(self, current_level, total_flow):
"""优化水泵运行方案"""
# 检查液位报警
alarms = self.check_level_alarm(current_level)
# 检查是否需要重新计算
if not self.should_recalculate(current_level):
return {"recalculate": False, "alarms": alarms}
# 计算总扬程
total_head = self.calculate_total_head(current_level)
if total_head not in self.current_pump_data:
raise ValueError(f"扬程 {total_head}m 不在数据范围内 (7-14m)")
data = self.current_pump_data[total_head]
min_flow = min(data['flow'])
max_flow = max(data['flow'])
best_solution = None
best_power = float('inf')
# 方案1: 1台变频泵
if min_flow <= total_flow <= max_flow:
freq, power = self.interpolate_frequency_power(total_flow, total_head)
solution = {
"scheme": "1台变频泵",
"variable_pumps": 1,
"fixed_pumps": 0,
"frequency": freq,
"total_power": power,
"flow_per_variable_pump": total_flow,
"fixed_pump_flow_per_pump": 0
}
if power < best_power:
best_solution = solution
best_power = power
# 方案2: 2台变频泵
flow_per_pump = total_flow / 2
if min_flow <= flow_per_pump <= max_flow:
freq, single_power = self.interpolate_frequency_power(flow_per_pump, total_head)
total_power = 2 * single_power
solution = {
"scheme": "2台变频泵",
"variable_pumps": 2,
"fixed_pumps": 0,
"frequency": freq,
"total_power": total_power,
"flow_per_variable_pump": flow_per_pump,
"fixed_pump_flow_per_pump": 0
}
if total_power < best_power:
best_solution = solution
best_power = total_power
# 方案3: 2台变频泵 + 1台工频泵
fixed_pump_flow = data['flow'][0] # 工频泵在最高频率时的流量
remaining_flow = total_flow - fixed_pump_flow
if remaining_flow > 0:
flow_per_variable = remaining_flow / 2
if min_flow <= flow_per_variable <= max_flow:
freq, single_power = self.interpolate_frequency_power(flow_per_variable, total_head)
fixed_pump_power = data['power'][0] # 工频泵在最高频率时的功率
total_power = 2 * single_power + fixed_pump_power
solution = {
"scheme": "2台变频泵 + 1台工频泵",
"variable_pumps": 2,
"fixed_pumps": 1,
"frequency": freq,
"total_power": total_power,
"flow_per_variable_pump": flow_per_variable,
"fixed_pump_flow_per_pump": fixed_pump_flow
}
if total_power < best_power:
best_solution = solution
best_power = total_power
# 方案4: 2台变频泵 + 2台工频泵
fixed_pumps_flow = 2 * data['flow'][0]
remaining_flow = total_flow - fixed_pumps_flow
if remaining_flow > 0:
flow_per_variable = remaining_flow / 2
if min_flow <= flow_per_variable <= max_flow:
freq, single_power = self.interpolate_frequency_power(flow_per_variable, total_head)
fixed_pump_power = data['power'][0]
total_power = 2 * single_power + 2 * fixed_pump_power
solution = {
"scheme": "2台变频泵 + 2台工频泵",
"variable_pumps": 2,
"fixed_pumps": 2,
"frequency": freq,
"total_power": total_power,
"flow_per_variable_pump": flow_per_variable,
"fixed_pump_flow_per_pump": fixed_pump_flow
}
if total_power < best_power:
best_solution = solution
best_power = total_power
if best_solution is None:
raise ValueError(f"无法找到合适的泵组配置,总流量 {total_flow} m³/h 超出范围")
# 更新上次计算的液位
self.last_level = current_level
result = {
"recalculate": True,
"total_head": total_head,
"best_solution": best_solution,
"alarms": alarms
}
return result
def calculate_energy_saving(self, flow, level):
"""
水泵节能方案计算接口
Args:
flow: 流量 (m³/h)
level: 液位 (m)
Returns:
tuple: (工频泵台数, 变频泵台数, 单台变频泵频率, 单台变频泵流量, 单台工频泵流量, 总功率)
"""
result = self.optimize_pump_operation(level, flow)
if not result["recalculate"]:
raise ValueError("液位变化未超过阈值,建议使用上次计算结果")
solution = result["best_solution"]
# 提取所需的输出参数
fixed_pumps = solution["fixed_pumps"] # 工频泵台数
variable_pumps = solution["variable_pumps"] # 变频泵台数
frequency = solution["frequency"] # 单台变频泵频率
variable_flow = solution["flow_per_variable_pump"] # 单台变频泵流量
fixed_flow = solution.get("fixed_pump_flow_per_pump", 0) # 单台工频泵流量
total_power = solution["total_power"] # 总功率
return (fixed_pumps, variable_pumps, frequency,
variable_flow, fixed_flow, total_power)
# 厂家调用接口类
class PumpEnergyOptimizerAPI:
"""
水泵能量优化器API - 供厂家调用
厂家只需要使用这个类的方法,不需要了解内部实现
"""
def __init__(self):
self._optimizer = PumpEnergyOptimizer()
def set_pump_parameters(self, pipe_resistance=None, dynamic_head=None,
high_level_alarm=None, low_level_alarm=None):
"""
设置水泵参数
Args:
pipe_resistance: 管阻 (米)
dynamic_head: 动扬程 (米)
high_level_alarm: 高液位报警值 (米)
low_level_alarm: 低液位报警值 (米)
Returns:
bool: 操作是否成功
"""
try:
return self._optimizer.set_pump_parameters(
pipe_resistance, dynamic_head, high_level_alarm, low_level_alarm)
except Exception as e:
print(f"设置水泵参数失败: {e}")
return False
def set_level_alarm(self, high_level_alarm, low_level_alarm):
"""
设置液位报警值
Args:
high_level_alarm: 高液位报警值 (米)
low_level_alarm: 低液位报警值 (米)
Returns:
bool: 操作是否成功
"""
try:
return self._optimizer.set_level_alarm(high_level_alarm, low_level_alarm)
except Exception as e:
print(f"设置液位报警值失败: {e}")
return False
def adjust_pump_data(self, head_to_adjust, flow_factor=1.0, power_factor=1.0, freq_factor=1.0):
"""
调整水泵数据
Args:
head_to_adjust: 需要调整的扬程值 (7-14)
flow_factor: 标准流量动态系数 (0-2)
power_factor: 标准功率动态系数 (0-2)
freq_factor: 输出频率动态系数 (0-2)
Returns:
bool: 操作是否成功
"""
try:
return self._optimizer.adjust_pump_data(head_to_adjust, flow_factor, power_factor, freq_factor)
except Exception as e:
print(f"调整水泵数据失败: {e}")
return False
def reset_pump_data(self):
"""
重置水泵数据为标准数据
Returns:
bool: 操作是否成功
"""
try:
return self._optimizer.reset_pump_data()
except Exception as e:
print(f"重置水泵数据失败: {e}")
return False
def calculate_energy_saving(self, flow, level):
"""
计算水泵节能方案
Args:
flow: 流量 (m³/h)
level: 液位 (m)
Returns:
tuple: (工频泵台数, 变频泵台数, 单台变频泵频率, 单台变频泵流量, 单台工频泵流量, 总功率)
如果计算失败,返回None
"""
try:
return self._optimizer.calculate_energy_saving(flow, level)
except Exception as e:
print(f"计算节能方案失败: {e}")
return None
# 简化的厂家调用接口函数
def create_pump_optimizer():
"""
创建水泵优化器实例
Returns:
PumpEnergyOptimizerAPI: 水泵优化器API实例
"""
return PumpEnergyOptimizerAPI()
3 创建编译和部署文件
setup.py - 安装脚本:
from setuptools import setup
from Cython.Build import cythonize
setup(
name="PumpEnergyOptimizer",
ext_modules=cythonize("pump_optimizer.pyx"),
zip_safe=False,
)
requirements.txt - 依赖列表:
cython>=0.29.0
setuptools>=45.0
4 编译过程
先在Ubuntu24.04中安装依赖,进入到项目文件夹,打开cmd:
# 创建虚拟环境
python3 -m venv myenv
# 激活虚拟环境
source myenv/bin/activate
pip install -r requirements.txt
# 使用后可以退出虚拟环境
# deactivate

执行编译:
python3 setup.py build_ext --inplace


验证编译结果,写一个python脚本,对so进行验证,其实就是调用其接口
# 引入生成的 pump_optimizer 模块
import pump_optimizer
def main():
# 创建水泵优化器 API 实例
optimizer = pump_optimizer.create_pump_optimizer()
# 1. 设置水泵参数
print("设置水泵参数:")
result = optimizer.set_pump_parameters(pipe_resistance=1.2, dynamic_head=1.5,
high_level_alarm=8.0, low_level_alarm=2.0)
print("设置结果:", result)
print()
# 2. 设置液位报警值
print("设置液位报警值:")
result = optimizer.set_level_alarm(high_level_alarm=7.0, low_level_alarm=1.0)
print("设置结果:", result)
print()
# 3. 调整水泵数据
print("调整水泵数据:")
result = optimizer.adjust_pump_data(head_to_adjust=12, flow_factor=1.1, power_factor=1.2, freq_factor=0.9)
print("调整结果:", result)
print()
# 4. 重置水泵数据
print("重置水泵数据:")
result = optimizer.reset_pump_data()
print("重置结果:", result)
print()
# 5. 计算节能方案
print("计算节能方案:")
flow = 1500 # 目标流量 (m³/h)
level = 4 # 当前液位 (m)
energy_saving_result = optimizer.calculate_energy_saving(flow, level)
print("节能方案计算结果:")
print(f"工频泵台数: {energy_saving_result[0]}")
print(f"变频泵台数: {energy_saving_result[1]}")
print(f"单台变频泵频率: {energy_saving_result[2]} Hz")
print(f"单台变频泵流量: {energy_saving_result[3]} m³/h")
print(f"单台工频泵流量: {energy_saving_result[4]} m³/h")
print(f"总功率: {energy_saving_result[5]} kW")
if __name__ == "__main__":
main()



被折叠的 条评论
为什么被折叠?



