Files
Brayton-Cycle-Optimization/brayton_cycle_test.py
T
2026-05-08 15:15:12 +08:00

980 lines
39 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
Created on Mon Dec 22 15:35:07 2025
"""
import ctREFPROP.ctREFPROP as ct
from scipy.optimize import minimize_scalar
import numpy as np
import matplotlib.pyplot as plt
class CO2PropertyCalculator():
"""二氧化碳物性计算"""
def __init__(self, refprop_path = None):
"""初始化库"""
self.rp = ct.REFPROPFunctionLibrary(refprop_path)
# 设置流体文件
self.rp.SETUPdll(1, 'CO2.FLD', 'HMX.BNC', 'DEF')
# 设置单位
self.rp.SETUPdll(2, 'SI', 'SI', 'DEF')
self.z = [1.0]
self.mw = self.rp.WMOLdll(self.z)
def calculate_properties(self, T=None, P=None, h=None, s=None):
"""计算二氧化碳物性"""
if T is not None and P is not None:
# 已知Tp
result = self.rp.TPFLSHdll(T, P, self.z)
properties = {
'T': T,
'P': P,
'h': result.h,
's': result.s,
}
elif P is not None and h is not None:
# 已知Ph
result = self.rp.PHFLSHdll(P, h, self.z)
properties = {
'T': result.T,
'P': P,
'h': h,
's': result.s,
}
elif T is not None and h is not None:
# 已知Th
result = self.rp.THFLSHdll(T, h, self.z)
properties = {
'T': T,
'P': result.P,
'h': h,
's': result.s,
}
elif P is not None and s is not None:
# 已知Ps
result = self.rp.PSFLSHdll(P, s, self.z)
properties = {
'T': result.T,
'P': P,
'h': result.h,
's': s,
}
else:
raise ValueError("提供的参数不足")
if result.ierr > 0:
raise ValueError(f"REFPROP计算错误:{result.ierr}")
# 补充提取的物性,这里由于后续还要使用,不进行参数变换
properties['D'] = result.D
properties['cp'] = result.Cp
properties['cv'] = result.Cv,
return properties
class Compressor():
"""压缩机类"""
def __init__(self, name, eff):
"""
初始化参数
name: 名称
eff: 等熵效率
Wc: 压缩功
inlet_state: 入口参数
outlet_state: 出口参数
outlet_state_is: 等熵状态下出口参数
"""
self.name = name
self.eff = eff
self.variables = None
def calculator(self, p_in, T_in, p_out, property_calculator):
# 先计算熵值
inlet_state = property_calculator.calculate_properties(T=T_in, P=p_in)
mw = property_calculator.mw
s = inlet_state['s']
h_in = inlet_state['h']
outlet_state_is = property_calculator.calculate_properties(P=p_out, s=s)
h_out_is = outlet_state_is['h']
h_out = h_in + (h_out_is - h_in) / self.eff
outlet_state = property_calculator.calculate_properties(P=p_out, h=h_out)
Wc = h_out - h_in
T_out = outlet_state['T']
# 计算结果
self.variables = {
'name': self.name,
'inlet_state':{
'P': p_in, # 压强(kPa)
'T': T_in,
'h': h_in/mw, # 比焓(J/mol)->(J/kg)
's': s/mw, # 比熵(J/mol.K)->(J/kg.K)
},
'outlet_state':{
'P': p_out, # 压强(kPa)
'T': T_out,
'h': h_out/mw, # 比焓(kJ/mol)->(kJ/kg)
's': s/mw, # 比熵(kJ/mol.K)->(kJ/kg.K)
},
'eff': self.eff,
'Wc': Wc/mw, # 压缩功(kJ/mol)->(kJ/kg)
'pi': p_out / p_in
}
class Turbine():
"""透平类"""
def __init__(self, name, eff):
"""
初始化参数
name: 名称
eff: 透平效率
"""
self.name = name
self.eff = eff
self.variables = None
def calculator(self, p_in, T_in, p_out, property_calculator):
"""涡轮参数计算"""
inlet_state = property_calculator.calculate_properties(P=p_in, T=T_in)
mw = property_calculator.mw
s = inlet_state['s']
h_in = inlet_state['h']
outlet_state_is = property_calculator.calculate_properties(P=p_out, s=s)
h_out_is = outlet_state_is['h']
h_out = h_in - (h_in - h_out_is) * self.eff
outlet_state = property_calculator.calculate_properties(P=p_out, h=h_out)
T_out = outlet_state['T']
Wt = h_in - h_out
self.variables = {
'name': self.name,
'inlet_state':{
'P': p_in, # 压强(kPa)
'T': T_in,
'h': h_in/mw, # 比焓(J/mol)->(J/kg)
's': s/mw, # 比熵(J/mol.K)->(J/kg.K)
},
'outlet_state':{
'P': p_out, # 压强(kPa)
'T': T_out,
'h': h_out/mw, # 比焓(J/mol)->(J/kg)
's': s/mw, # 比熵(J/mol.K)->(J/kg.K)
},
'eff': self.eff,
'Wt': Wt/mw, # 透平做功(J/mol)->(J/kg)
'pi': p_in / p_out
}
class Recuperator():
"""换热器类"""
def __init__(self, name, eff, x=0):
"""
初始化参数
name: 名称
eff: 换热效率(基于焓的计算方法)
"""
self.name = name
self.eff = eff
self.Q_ex = None
self.variables = None
self.x = x
def calculator(self, cold_inlet_state, hot_inlet_state, bypass_info, ploss, property_calculator):
"""
计算换热器两侧参数,默认逆流
bypass_info: 是否存在分流,0为不存在,1为存在
下标含义
----------
1: 换热器冷端入口
2: 换热器冷端出口
3: 换热器热端入口
4: 换热器热端出口
ass: 迭代中间变量,假设值
"""
# 计算两入口参数, 这里单位是kg
p1 = cold_inlet_state['P']
T1 = cold_inlet_state['T']
h1 = cold_inlet_state['h']
p2 = p1 * (1 - ploss)
p3 = hot_inlet_state['P']
T3 = hot_inlet_state['T']
h3 = hot_inlet_state['h']
p4 = p3 * (1 - ploss)
mw = property_calculator.mw
# 设定质量流量
m_cold = (1-self.x) if bypass_info == 1 else 1.0
m_hot = 1.0
# =============================================================================
# # 采用焓差效能的方式来计算换热器进出口参数
# # 假设最大温差发生在冷端, 计算冷端出口温度和比焓
# cold_outlet_state = property_calculator.calculate_properties(T=T3, P=p2)
# h2 = cold_outlet_state['h'] / mw
# Q_ass_cold = m_cold * abs(h2 - h1)
#
# # 假设最大温差发生在热端, 计算热端出口温度和比焓
# hot_outlet_state = property_calculator.calculate_properties(T=T1, P=p4)
# h4 = hot_outlet_state['h'] / mw
# Q_ass_hot = m_hot * abs(h3 - h4)
#
# # 比较两个可能的Q,取最小值与焓差效能的乘积作为实际换热量
# self.Q_ex = min(Q_ass_hot, Q_ass_cold) * self.eff
# # 由实际换热量计算出口焓和出口状态
# h2 = h1 + self.Q_ex / m_cold
# h4 = h3 - self.Q_ex / m_hot
# cold_outlet_state = property_calculator.calculate_properties(P=p2, h=h2*mw)
# hot_outlet_state = property_calculator.calculate_properties(P=p4, h=h4*mw)
# T2 = cold_outlet_state['T']
# T4 = hot_outlet_state['T']
# =============================================================================
# 采用温差效能的方式来计算换热器进出口参数
T_ass_max = abs(T1 - T3)
# 假设最大温差发生在冷端, 计算冷端出口温度和比焓
T2 = T1 + T_ass_max * self.eff
cold_outlet_state = property_calculator.calculate_properties(T=T2, P=p2)
h2 = cold_outlet_state['h'] / mw
Q_ass_cold = m_cold * abs(h2 - h1)
# 假设最大温差发生在热端, 计算热端出口温度和比焓
T4 = T3 - T_ass_max * self.eff
hot_outlet_state = property_calculator.calculate_properties(T=T4, P=p4)
h4 = hot_outlet_state['h'] / mw
Q_ass_hot = m_hot * abs(h3 - h4)
# 比较两个可能的Q,取最小值与焓差效能的乘积作为实际换热量
self.Q_ex = min(Q_ass_hot, Q_ass_cold)
# 由实际换热量计算出口焓和出口状态
h2 = h1 + self.Q_ex / m_cold
h4 = h3 - self.Q_ex / m_hot
cold_outlet_state = property_calculator.calculate_properties(P=p2, h=h2*mw)
hot_outlet_state = property_calculator.calculate_properties(P=p4, h=h4*mw)
T2 = cold_outlet_state['T']
T4 = hot_outlet_state['T']
# 拼装变量
self.variables = {
'name': self.name,
'cold_inlet_state':{
'P': p1,
'T': T1,
'h': h1,
's': cold_inlet_state['s']
},
'cold_outlet_state':{
'P': p2,
'T': cold_outlet_state['T'],
'h': h2,
's': cold_outlet_state['s']/mw
},
'hot_inlet_state':{
'P': p3,
'T': T3,
'h': h3,
's': hot_inlet_state['s']
},
'hot_outlet_state':{
'P': p4,
'T': T4,
'h': h4,
's': hot_outlet_state['s']/mw
},
'eff': self.eff,
'Q_exchange': self.Q_ex
}
def check_pinch_point(self, property_calculator, num_segments=20):
"""
换热器内部夹点校验
将换热量均分为 num_segments 段,检查内部每个微元的冷热流体温度
"""
h_cold_in = self.variables['cold_inlet_state']['h']
h_hot_in = self.variables['hot_inlet_state']['h']
p_cold = self.variables['cold_inlet_state']['P']
p_hot = self.variables['hot_inlet_state']['P']
m_cold = (1 - self.x) if self.name == "Low Temperature recuprerator" else 1.0
m_hot = 1.0
dQ = self.Q_ex / num_segments
# 沿冷流体流动方向步进检查
for i in range(num_segments + 1):
q_current = i * dQ
# 当前微元截面的焓值
h_cold_local = h_cold_in + q_current / m_cold
h_hot_local = (h_hot_in - self.Q_ex / m_hot) + q_current / m_hot
# 查温度
T_cold_local = property_calculator.calculate_properties(P=p_cold, h=h_cold_local * property_calculator.mw)['T']
T_hot_local = property_calculator.calculate_properties(P=p_hot, h=h_hot_local * property_calculator.mw)['T']
# 如果热流体温度低于等于冷流体温度 (设定一个 0.1K 的最小逼近温差容差)
if T_hot_local - T_cold_local < 0.1:
return False # 发生温度交叉,物理不可行!
return True # 校验通过
class Heater():
"""加热器类"""
def __init__(self, name):
self.name = name
self.variables = None
def calculator(self, inlet_state, outlet_state):
h_in = inlet_state['h']
h_out = outlet_state['h']
Q_input = h_out - h_in
self.variables = {
'name': self.name,
'inlet_state':{
'P': inlet_state['P'], # 压强(kPa)
'T': inlet_state['T'],
'h': inlet_state['h'],
's': inlet_state['s'],
},
'outlet_state':{
'P': outlet_state['P'], # 压强(kPa)
'T': outlet_state['T'],
'h': outlet_state['h'],
's': outlet_state['s'],
},
'Q_in': Q_input,
}
class Condenser():
"""冷凝器类"""
def __init__(self, name):
self.name = name
self.variables = None
def calculator(self, inlet_state, outlet_state):
h_in = inlet_state['h']
h_out = outlet_state['h']
Q_output = h_in - h_out
self.variables = {
'name': self.name,
'inlet_state':{
'P': inlet_state['P'], # 压强(kPa)
'T': inlet_state['T'],
'h': inlet_state['h'],
's': inlet_state['s'],
},
'outlet_state':{
'P': outlet_state['P'], # 压强(kPa)
'T': outlet_state['T'],
'h': outlet_state['h'],
's': outlet_state['s'],
},
'Q_out': Q_output,
}
class Concentrator():
"""汇流组件"""
def __init__(self, name):
self.name = name
self.variables = None
def calculator(self, inlet_state_bypass, inlet_state_mroad, x, property_calculator):
h_in_bypass = inlet_state_bypass['h']
h_in_mroad = inlet_state_mroad['h']
p_in = inlet_state_bypass['P']
mw = property_calculator.mw
h_out = x * h_in_bypass + (1-x) * h_in_mroad
outlet_state = property_calculator.calculate_properties(P=p_in, h=h_out*mw)
self.variables = {
'name': self.name,
'inlet_state_bypass': inlet_state_bypass,
'inlet_state_mroad': inlet_state_mroad,
'outlet_state':{
'P': p_in,
'T': outlet_state['T'],
'h': h_out,
's': outlet_state['s']/mw
}
}
class BraytonCycle():
"""循环计算"""
def __init__(self, name, refprop_path = "C:/Program Files (x86)/REFPROP 10.0+/REFPROP"):
self.name = name
self.property_calculator = None
self.compressor = None
self.turbine = None
self.recuperator = None
self.heater = None
self.condenser = None
self.concentrator = None
self.refprop_path = refprop_path
self.property_calculator = CO2PropertyCalculator(self.refprop_path)
def cycle_eff_calculator(self):
if type(self.compressor) == list:
Wc = (self.compressor[0].variables['Wc'] +
self.compressor[1].variables['Wc'])
else:
Wc = self.compressor.variables['Wc']
Wt = self.turbine.variables['Wt']
Q_input = self.heater.variables['Q_in']
cycle_eff = (Wt - Wc) / Q_input
return cycle_eff
def SC(self, T_low, T_high, p_low, p_high, param = None):
if param == None:
param = {
'compressor_eff': 0.98,
'turbine_eff': 0.95
}
# 定义循环组件
self.heater = Heater(name = "Main heater")
self.condenser = Condenser(name = "Main condenser")
self.compressor = Compressor(name = "Main compressor", eff = param['compressor_eff'])
self.turbine = Turbine(name = "Turbine", eff = param['turbine_eff'])
# 计算循环参数
self.compressor.calculator(p_low, T_low, p_high, self.property_calculator)
self.turbine.calculator(p_high, T_high, p_low, self.property_calculator)
self.heater.calculator(self.compressor.variables['outlet_state'], self.turbine.variables['inlet_state'])
self.condenser.calculator(self.turbine.variables['outlet_state'], self.compressor.variables['inlet_state'])
# 计算循环效率
cycle_eff = self.cycle_eff_calculator()
return cycle_eff
def SRC(self, T_low, T_high, p_low, p_high, param = None):
if ('recuperator_eff' not in param) or param == None:
param = {
'compressor_eff': 0.98,
'turbine_eff': 0.95,
'recuperator_eff': 0.85
}
# 定义循环组件
self.heater = Heater(name = "Main heater")
self.condenser = Condenser(name = "Main condenser")
self.compressor = Compressor(name = "Main compressor", eff = param['compressor_eff'])
self.turbine = Turbine(name = "Turbine", eff = param['turbine_eff'])
self.recuperator = Recuperator(name = "Recuperator", eff = param['recuperator_eff'])
# 计算循环参数
self.compressor.calculator(p_low, T_low, p_high, self.property_calculator)
self.turbine.calculator(p_high, T_high, p_low, self.property_calculator)
self.recuperator.calculator(self.compressor.variables['outlet_state'],
self.turbine.variables['outlet_state'], 0,
self.property_calculator)
self.condenser.calculator(self.recuperator.variables['hot_outlet_state'],
self.compressor.variables['inlet_state'])
self.heater.calculator(self.recuperator.variables['cold_outlet_state'],
self.turbine.variables['inlet_state'])
# 计算循环效率
cycle_eff = self.cycle_eff_calculator()
return cycle_eff
def RC(self, T_low, T_high, p_low, p_high, ploss, param = None):
if ('recompressor_eff' not in param or
'highT_recuperator_eff' not in param or
'x' not in param or
param == None):
param = {
'compressor_eff': 0.98,
'turbine_eff': 0.95,
'recuperator_eff': 0.85,
'recompressor_eff': 0.98,
'highT_recuperator_eff': 0.85,
'x': 0.9
}
self.x = param['x']
# 定义循环组件
self.heater = Heater(name = "Main heater")
self.condenser = Condenser(name = "Main_condenser")
self.turbine = Turbine(name = "Main Turbine",
eff = param['turbine_eff'])
main_compressor = Compressor(name = "Main compressor",
eff = param['compressor_eff'])
recompressor = Compressor(name = "Recompressor",
eff = param['recompressor_eff'])
lrecuperator = Recuperator(name = "Low Temperature recuprerator",
eff = param['recuperator_eff'],
x = self.x)
hrecuperator = Recuperator(name = "High Temperature recuperator",
eff = param['highT_recuperator_eff'])
self.concentrator = Concentrator(name = "Concentrator")
self.recuperator = []
self.compressor = []
# 计算组件进出口参数
# 先算压缩机和涡轮
main_compressor.calculator(p_low, T_low, p_high, self.property_calculator)
self.turbine.calculator(p_high*(1-ploss)**3,
T_high, p_low*(1-ploss)**(-3),
self.property_calculator)
# 假定低温回热器出口参数并进行迭代
mw = self.property_calculator.mw
T_hr_inlet = ((self.turbine.variables['outlet_state']['T']
+ main_compressor.variables['outlet_state']['T'])/2)
# T_lr_inlet = self.turbine.variables['outlet_state']['T'] * 1.01
max_iter = 300
relax_fac = 0.4
for i in range(max_iter):
hr_inlet_state_hot_mol = self.property_calculator.calculate_properties(P=p_high*(1-ploss), T=T_hr_inlet)
# 单位转换成mol
hr_inlet_state_hot = {
'P': hr_inlet_state_hot_mol['P'],
'T': hr_inlet_state_hot_mol['T'],
'h': hr_inlet_state_hot_mol['h']/mw,
's': hr_inlet_state_hot_mol['s']/mw
}
hrecuperator.calculator(hr_inlet_state_hot,
self.turbine.variables['outlet_state'], 0,
ploss, self.property_calculator)
lrecuperator.calculator(main_compressor.variables['outlet_state'],
hrecuperator.variables['hot_outlet_state'], 1,
ploss, self.property_calculator)
recompressor.calculator(p_in = p_low/(1-ploss), p_out = p_high*(1-ploss),
T_in = lrecuperator.variables['hot_outlet_state']['T'],
property_calculator = self.property_calculator)
self.concentrator.calculator(recompressor.variables['outlet_state'],
lrecuperator.variables['cold_outlet_state'],
self.x, self.property_calculator)
Tc_outlet = self.concentrator.variables['outlet_state']['T']
err = abs(Tc_outlet - T_hr_inlet)
if err <= 1e-5:
break
if i == max_iter - 1:
raise ValueError(f"迭代次数超过范围,当前误差{err:.4f}")
T_hr_inlet = relax_fac * Tc_outlet + (1 - relax_fac) * T_hr_inlet
hrecuperator.calculator(self.concentrator.variables['outlet_state'],
self.turbine.variables['outlet_state'], 0,
ploss, self.property_calculator)
lrecuperator.calculator(main_compressor.variables['outlet_state'],
hrecuperator.variables['hot_outlet_state'], 1,
ploss, self.property_calculator)
main_compressor.variables['Wc'] *= (1-self.x)
recompressor.variables['Wc'] *= self.x
self.recuperator.append(lrecuperator)
self.recuperator.append(hrecuperator)
self.compressor.append(main_compressor)
self.compressor.append(recompressor)
self.condenser.calculator(lrecuperator.variables['hot_outlet_state'],
main_compressor.variables['inlet_state'])
self.condenser.variables['Q_out'] *= (1-self.x)
self.heater.calculator(hrecuperator.variables['cold_outlet_state'],
self.turbine.variables['inlet_state'])
# 计算循环效率
cycle_eff = self.cycle_eff_calculator()
return cycle_eff
def base_params_single_optimize(self, fixed_var, base_params, target_var_name, bounds):
"""
组件性能单变量优化器
: 固定边界条件
: 默认参数
: 优化变量名称
: 变量范围
"""
if target_var_name not in base_params:
raise ValueError(f"参数{target_var_name}不在参数字典中")
def opt_fun(opt_var):
# 复制变量字典
opt_param = base_params.copy()
# 修改要优化的变量为参数
opt_param[target_var_name] = opt_var
# 带入循环参数计算
try:
eff = self.RC(
T_low = fixed_var['T_low'],
T_high= fixed_var['T_high'],
p_low = fixed_var['p_low'],
p_high = fixed_var['p_high'],
ploss = fixed_var['ploss'],
param = opt_param)
return -eff
except Exception as e:
return 0.0 # 遇到物性计算崩溃时返回极差值
res = minimize_scalar(opt_fun, bounds=bounds, method='bounded')
if res.success:
print(f"✅ 优化完成!")
print(f"👉 最佳 {target_var_name} = {res.x:.4f}")
print(f"👉 此时系统最高效率 = {-res.fun:.2%}\n")
else:
print("❌ 优化失败。")
return res
def fixed_params_single_optimize(self, fixed_params, target_var_name, params, bounds):
"""
边界条件单变量优化器
: 固定边界条件
: 默认参数
: 优化变量名称
: 变量范围
"""
if target_var_name not in fixed_params:
raise ValueError(f"参数{target_var_name}不在参数字典中")
def opt_fun(opt_var):
# 复制变量
opt_params = fixed_params.copy()
# 变量替换
opt_params[target_var_name] = opt_var
# 带入循环
try:
eff = self.RC(T_low = opt_params['T_low'],
T_high = opt_params['T_high'],
p_low = opt_params['p_low'],
p_high = opt_params['p_high'],
ploss = opt_params['ploss'],
param = params)
return -eff
except Exception as e:
return 0.0
res = minimize_scalar(opt_fun, bounds=bounds, method='bounded')
if res.success:
print(f"✅ 优化完成!")
print(f"👉 最佳 {target_var_name} = {res.x:.4f}")
print(f"👉 此时系统最高效率 = {-res.fun:.2%}\n")
else:
print("❌ 优化失败。")
return res
def plot_optimization_landscape(self, fixed_params, params, target_var_name, bounds, res, num_points=50):
"""
绘制单变量优化地形图
:param target_var_name: 要扫描和优化的变量名(如 'x')
:param bounds: 扫描和优化的范围 (min, max)
:param num_points: 扫描的采样点数量,越大曲线越平滑,但计算越慢
"""
print(f"开始对【{target_var_name}】进行区间扫描,共计算 {num_points} 个点...")
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows 用黑体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
# 1. 生成扫描数组
x_vals = np.linspace(bounds[0], bounds[1], num_points)
eff_vals = []
valid_x = [] # 记录那些没有报错的 x
if target_var_name not in fixed_params:
# 2. 遍历计算曲线上的点
for val in x_vals:
current_param = params.copy()
current_param[target_var_name] = val
try:
# 调用你的黑盒物理模型(注意:这里取正效率用于画图)
eff = self.RC(
T_low=fixed_params['T_low'],
T_high=fixed_params['T_high'],
p_low=fixed_params['p_low'],
p_high=fixed_params['p_high'],
ploss=fixed_params['ploss'],
param=current_param
)
# 如果系统加了夹点校验且没通过,可能会返回 None 或者抛异常
# 这里确保只有成功的点才画上去
eff_vals.append(eff * 100) # 乘以 100 转换为百分比
valid_x.append(val)
except Exception as e:
# 如果某个 x 导致计算崩溃,我们跳过这个点,不画它
pass
else:
for val in x_vals:
current_param = fixed_params.copy()
current_param[target_var_name] = val
try:
# 调用你的黑盒物理模型(注意:这里取正效率用于画图)
eff = self.RC(
T_low=current_param['T_low'],
T_high=current_param['T_high'],
p_low=current_param['p_low'],
p_high=current_param['p_high'],
ploss=current_param['ploss'],
param=params
)
# 如果系统加了夹点校验且没通过,可能会返回 None 或者抛异常
# 这里确保只有成功的点才画上去
eff_vals.append(eff * 100) # 乘以 100 转换为百分比
valid_x.append(val)
except Exception as e:
# 如果某个 x 导致计算崩溃,我们跳过这个点,不画它
pass
print("扫描完成!正在使用优化器寻找精确最高点...")
# 4. 开始绘图
plt.figure(figsize=(8, 6), dpi=120) # 设置画布大小和清晰度
# 画出目标函数曲线
plt.plot(valid_x, eff_vals, linestyle='-', color='#1f77b4', linewidth=2, label='系统热效率曲线')
# 如果优化成功,用醒目的红星标出最优点
if res.success:
best_x = res.x
best_eff = -res.fun * 100
plt.scatter(best_x, best_eff, color='red', marker='*', s=200, zorder=5, label=f'最优点 ({best_x:.4f}, {best_eff:.2f}%)')
# 画辅助虚线对齐坐标轴
plt.axvline(x=best_x, color='gray', linestyle='--', alpha=0.6)
plt.axhline(y=best_eff, color='gray', linestyle='--', alpha=0.6)
else:
print("优化结果未输入!")
# 设置图表装饰
plt.title(f'系统热效率随 {target_var_name} 的变化趋势', fontsize=14)
plt.xlabel(f'优化变量: {target_var_name}', fontsize=12)
plt.ylabel('循环热效率 η (%)', fontsize=12)
plt.grid(True, linestyle=':', alpha=0.7)
plt.legend(fontsize=11)
# 显示图像
plt.tight_layout()
plt.show()
# 调用测试
# plot_optimization_landscape('x', bounds=(0.6, 0.95), num_points=40)
def sweep_and_optimize(self, fixed_params, params, sweep_var, sweep_bounds, opt_var, opt_bounds, num_points=50):
"""
带内部动态优化的单变量扫描器 (极度通用版)
:param fixed_params: 固定的边界条件字典
:param params: 组件性能参数字典
:param sweep_var: 你要扫描/遍历的变量名 (例如 'T_low')
:param sweep_bounds: 扫描变量的范围 (min, max)
:param opt_var: 在每个扫描点下,你需要动态寻找最优值的变量名 (例如 'x')
:param opt_bounds: 优化变量的搜索范围 (min, max)
:param num_points: 扫描点数
"""
print(f"\n🚀 开始执行嵌套扫描:")
print(f" - 扫描变量 (X轴): 【{sweep_var}】 范围 {sweep_bounds}")
print(f" - 内部动态优化变量: 【{opt_var}】 范围 {opt_bounds}")
# 1. 生成扫描节点
sweep_vals = np.linspace(sweep_bounds[0], sweep_bounds[1], num_points)
# 记录数据的列表
valid_sweep_vals = []
best_effs = []
best_opt_vals = []
# 2. 开始逐点扫描
for s_val in sweep_vals:
# 【核心1:每次必须使用干净的字典副本】
current_fixed = fixed_params.copy()
current_param = params.copy()
# 判断扫描变量是属于 fixed_params 还是 params,并赋值
if sweep_var in current_fixed:
current_fixed[sweep_var] = s_val
elif sweep_var in current_param:
current_param[sweep_var] = s_val
else:
raise ValueError(f"找不到扫描变量: {sweep_var}")
# 3. 定义内部优化目标函数 (闭包)
def inner_objective(guess_val):
# 将优化器猜的值赋给 opt_var
current_param[opt_var] = guess_val
try:
# 调用黑盒计算
eff = self.RC(
T_low=current_fixed['T_low'],
T_high=current_fixed['T_high'],
p_low=current_fixed['p_low'],
p_high=current_fixed['p_high'],
ploss=current_fixed['ploss'],
param=current_param
)
# 【预留口:此处可加入换热器内部夹点校验】
# 取出两个换热器进行夹点校验
for rec in self.recuperator:
if not rec.check_pinch_point(self.property_calculator):
return 0.0 # 核心!如果交叉了,直接返回 0 效率,强迫优化器换参数
return -eff
except Exception:
return 0.0
# 4. 调用一维优化器
res = minimize_scalar(inner_objective, bounds=opt_bounds, method='bounded')
# 5. 结果校验与存储
if res.success and -res.fun > 0:
best_eff = -res.fun * 100
best_opt_val = res.x
valid_sweep_vals.append(s_val)
best_effs.append(best_eff)
best_opt_vals.append(best_opt_val)
print(f"✔️ {sweep_var} = {s_val:.2f} | 寻得最优 {opt_var} = {best_opt_val:.4f} | 最高效率 = {best_eff:.2f}%")
else:
print(f"❌ {sweep_var} = {s_val:.2f} | 优化失败或物理无解,已跳过")
# 6. 调用画图方法 (将画图剥离,保持代码干净)
self._plot_results(sweep_var, valid_sweep_vals, best_effs, opt_var, best_opt_vals)
return valid_sweep_vals, best_effs, best_opt_vals
def _plot_results(self, sweep_var, x_data, y_eff_data, opt_var, y_opt_data):
"""专门用来画图的内部方法,支持双Y轴"""
if not x_data:
print("没有有效数据可供绘制!")
return
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
fig, ax1 = plt.subplots(figsize=(9, 6), dpi=120)
# 画左Y轴:最高效率曲线
color1 = '#1f77b4'
ax1.set_xlabel(f'扫描变量: {sweep_var}', fontsize=12)
ax1.set_ylabel('最优循环热效率 η (%)', color=color1, fontsize=12)
ax1.plot(x_data, y_eff_data, color=color1, linewidth=2.5, label='系统热效率')
ax1.tick_params(axis='y', labelcolor=color1)
ax1.grid(True, linestyle=':', alpha=0.6)
# 画右Y轴:对应的最优分流量走势
ax2 = ax1.twinx()
color2 = '#d62728'
ax2.set_ylabel(f'匹配的最优动态变量: {opt_var}', color=color2, fontsize=12)
ax2.plot(x_data, y_opt_data, color=color2, linestyle='--', linewidth=2, label=f'最优 {opt_var} 值')
ax2.tick_params(axis='y', labelcolor=color2)
plt.title(f'系统最高效率及对应的最优 {opt_var} 随 {sweep_var} 的变化', fontsize=14)
fig.tight_layout()
plt.show()
if __name__ == "__main__":
brayton1 = BraytonCycle(name = "simple brayton cycle test")
T_high = 650+273.15
T_low = 42+273.15
p_high = 20.0e6
p_low = 9.09e6
fixed_var = {
'T_high': 650+273.15,
'T_low': 42+273.15,
'p_high': 20.0e3,
'p_low': 8.16e3,
'ploss': 0.01
}
# param = {
# 'compressor_eff': 0.9,
# 'turbine_eff': 0.93,
# 'recuprator_eff': 0.96
# }
# =========================================================================
# 焓差效能参数定义
# param = {
# 'x': 0.279,
# 'compressor_eff': 0.9,
# 'recompressor_eff': 0.855,
# 'turbine_eff': 0.93,
# 'recuperator_eff': 0.9354,
# 'highT_recuperator_eff': 0.8857
# }
# =========================================================================
# eff = brayton1.simple_brayton_cycle(T_low, T_high, p_low/1e3, p_high/1e3, param)
#
param = {
'x': 0.279,
'compressor_eff': 0.9,
'recompressor_eff': 0.9,
'turbine_eff': 0.93,
'recuperator_eff': 0.94,
'highT_recuperator_eff': 0.96
}
ploss = 0.01
eff = brayton1.RC(T_low, T_high, p_low/1e3, p_high/1e3, ploss, param)
c = brayton1.compressor
h = brayton1.heater
cond = brayton1.condenser
conc = brayton1.concentrator.variables
t = brayton1.turbine
r = brayton1.recuperator
vl = brayton1.recuperator[0].variables
vh = brayton1.recuperator[1].variables
Wc = brayton1.compressor[0].variables['Wc'] + brayton1.compressor[1].variables['Wc']
# Wc = brayton1.compressor.variables['Wc']
Wt = brayton1.turbine.variables['Wt']
Q_input = brayton1.heater.variables['Q_in']
Q_output = brayton1.condenser.variables['Q_out']
print(Q_input+Wc-(Q_output+Wt))
print((Wt - Wc)/Q_input)
# res_x = brayton1.base_params_single_optimize(fixed_var = fixed_var,
# base_params = param,
# target_var_name = 'x',
# bounds = (0.1,0.5))
# res_min_T = brayton1.fixed_params_single_optimize(fixed_params = fixed_var,
# target_var_name = 'T_low',
# params = param,
# bounds = (30+273.15, 60+273.15))
x_vals, eff_vals, opt_vals = brayton1.sweep_and_optimize(
fixed_params=fixed_var,
params=param,
sweep_var='T_low', # 扫描变量
sweep_bounds=(30+273.15, 60+273.15),
opt_var='x', # 动态优化变量
opt_bounds=(0.1, 0.5),
num_points=30)
# refprop_path = "C:/Program Files (x86)/REFPROP 10.0+/REFPROP"
# recuprator = Recuperator(name='Main Recuprator', eff=param['recuprator_eff'])
# calculator = CO2PropertyCalculator(refprop_path)
# cold_inlet_state = brayton1.compressor.variables['outlet_state']
# hot_inlet_state = brayton1.turbine.variables['outlet_state']
# recuprator.calculator(hot_inlet_state, cold_inlet_state, calculator)
# print(recuprator.variables)
# self.cycle_eff = None
# self.compressors = []
# self.turbines = []
# self.recuperators = []
# self.heaters = []
# self.condensers = []
# def add_compressor(self, name, eff):
# """添加压缩机"""
# compressor = Compressor(name, eff)
# self.compressors.append(compressor)
# return compressor
# def add_turbine(self, name, eff):
# """添加透平"""
# turbine = Turbine(name, eff)
# self.turbines.append(turbine)
# return turbine
# def add_heater(self, name):
# heater = Heater(name)
# self.heaters.append(heater)
# return heater
# def add_condenser(self,name):
# condenser = Condenser(name)
# self.condensers.append(condenser)
# return condenser
# def efficiency_calculation(self):
# cycle_Wc = 0.0
# for compressor in self.compressors:
# cycle_Wc += compressor.Wc
# cycle_Wt = 0.0
# for turbine in self.turbines:
# cycle_Wt += turbine.Wt
# cycle_Q_in = 0.0
# for heater in self.heaters:
# cycle_Q_in += self.heater.Q_input
# cycle_Q_out = 0.0
# for condenser in self.condensers:
# cycle_Q_out += self.condenser.Q_output
# cycle_eff = (cycle_Wt - cycle_Wc - cycle_Q_out) / cycle_Q_in
# return cycle_eff