我想根据请求的电源配置文件优化 CHP plant 的操作。因此,我定义了一个功率配置文件,热电联产电厂应尽可能遵循该功率配置文件。 必须应用多个边界和约束来代表热电联产电厂的实际运行。例如,这包括 CHP 可以打开或关闭,并且在打开时,其功率调制只能设置为特定的百分比范围。
这是一个带有简短说明的最小工作示例:
import scipy.optimize as opt
import numpy as np
x = np.arange(200) # dummy x vector
poly_profile = np.array( # 7th degree polynome fit of profile
[-2.14104340e-11, 1.85108903e-08, -6.66697810e-06, 1.29239710e-03,
-1.45110876e-01, 9.40324129e+00, -3.24548750e+02, 4.60006330e+03])
poly_fun = np.poly1d(poly_profile) # make poly fun
profile = poly_fun(x[65:196])
x0 = np.zeros_like(profile) # all zeros as starting values
def optifun(x, profile): # define minimization fun
return - np.sum(profile * x)
bnds_hi = opt.Bounds(0.3, 1) # upper bounds
bnds_lo = opt.Bounds(0, 0) # lower bounds
res = opt.minimize(
optifun, x0, args=(profile), bounds=bnds_hi,
constraints={'type': 'eq', 'fun': lambda x: np.sum(x*40) - 2000},
method='SLSQP')
plt.plot(res.x)
plt.plot(profile)
所以这些是我想要使用的界限:
-
(x == 0) or (0.3 <= x <= 1)
,对于数组x
中的任何值
这意味着总 CHP 功率的调制程度 x 可以是 0(关闭)或>0.3
和<= 1
。但我可以指定下限或上限。仅指定上限就不可能“关闭 CHP”,而将下限设置为bnds_lo = opt.Bounds(0, 1)
将使热电联产电厂能够在不现实的运行点(功率调制的 0% 到 30% 之间)运行。
有什么方法可以使其在最小工作示例中指定的范围内工作吗?具体来说:我可以同时设置两种边界,例如bounds=[bnds_lo, bnds_hi]
吗?
我猜这是一个混合整数线性规划问题,但 COBYLA 或 SLSQP 不应该能够处理这个问题吗?如果没有:有什么解决方法吗?
以及我想使用的约束:
np.sum(x*40) - 450
将热输出限制在一定的热存储容量内。这里40是热输出功率,450是剩余存储容量。这相当容易实现。限制热电联产电厂的启动次数。作为一个例子,我们假设
bnds_lo = opt.Bounds(0, 1) # lower bounds res = opt.minimize( optifun, x0, args=(profile), bounds=bnds_lo, constraints={'type': 'eq', 'fun': lambda x: np.sum(x*40) - 1000}, method='SLSQP')
这导致热电联产厂运行 3 个阶段。有什么办法可以限制这个吗?我正在考虑添加一个特定的约束函数,该函数计算前导 0 之后的正差异,但我无法完成类似的工作(例如,因为大多数
x
不完全是 0,因为边界设置为(0, 1)
。但其他问题也可能是原因)...- 设置热电联产电厂的最短连续运行时间。这意味着至少有 5 个连续的
x != 0
应该是有利的。我想过尝试与上一点类似的方法(限制启动次数),但也无法找到有用的方法。这是迄今为止最不重要的问题。
为了解决这些问题我也尝试使用
scipy.optimize.LinearConstraings
和 NonlinearConstraings
但是 method='trust-constr'
需要一个 jac (据我在 github 上读到的,这似乎是一个错误),因此我无法使其工作。
有什么办法可以让我完成这项工作吗?特别是指定多个边界很重要。
提前致谢!
真诚的, 斯科蒂
最佳答案
profile * x0
在你的代码中给出
“ValueError:操作数无法与形状 (131,) (200,) 一起广播”。
只是猜测,是x_t
一个产品onoff_t * xon_t
与 onoff_t
= 0 或 1
和0.3 <= xon_t <= 1
在每个 t
在0 .. T
?
IE。对于 T = 5
有 2^5 种可能 onoff
序列,00000 00001 00010 .. 11111?
如果是这样,则最大化 sum 0:T w_t * onoff_t * xon_t
具有固定权重函数w_t
是微不足道的:
哪里w_t <= 0
:onoff_t = 0
, 关闭
哪里w_t > 0
:onoff_t = 1
、关于、以及xon_t = 1
,最大
所以这不是你的问题——请澄清一下。
如果onoff_t
进一步限制只能切换两次,0...1...0...,
那么可能的序列数量足够小,可以尝试所有序列,
沿着线:
def pulse_generator( T=200, minwidth=5 ):
""" -> arrays of T floats, 0... 1... 0... """
for t0 in xrange( 1, T ):
for t1 in xrange( t0 + minwidth, T ):
pulse = np.zeros( T )
pulse[t0:t1] = 1
yield pulse
for pulse in pulse_generator( T ):
print "pulse:", pulse
optimize myfunction( pulse * xon ), 0.3 <= xon <= 1
切换4次,0...1...0...1...0...,类似。
(对于给定的 T
有多少个这样的脉冲?
请参阅维基百科 Stars and bars --
太棒了。)
- 将时间 0:T 分成 10 部分,运行所有 2^10 = 1024 个开关序列
1a.仔细观察最好的——有什么模式吗? - 将其边缘移动半步,T/20。
另请参阅: 谷歌“离散优化”多重网格......和 Grid search .
关于python - 具有多个边界、约束和连续字段的 scipy.optimize,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52781901/