此示例显示如何最佳地安排两个燃气发电机,这意味着获得最多的收入减去费用。虽然该示例并不完全逼真,但它确实展示了如何考虑到依赖决策时间的成本。
对于基于求解器的方法,请参阅电力发电机最佳调度:基于求解器.
电力市场在不同时间有不同的价格。如果您有发电机提供电力,可以通过安排当价格高时,通过安排发电机来利用这种可变定价。假设您控制了两个生成器。每个发电机具有三个功率电平(关闭,低,高)。每个发电机在每个功率水平上具有指定的燃料消耗和电力生产速率。当发电机关闭时,燃料消耗为0。
您可以在一天内为每个半小时时间间隔分配给每个发电机的功率电平(24小时,所以48间隔)。根据历史记录,假设您知道每次间隔中收到的每兆瓦的收入(MWH)。此示例的数据来自澳大利亚能源市场运营商https://www.nemweb.com.au/REPORTS/CURRENT/
在2013年中期,并且是在他们的术语下使用的https:/
/
www。
aemo。
com。
非盟/
隐私和法律通知/
版权权限
.
加载调解;%获取poolPrice,这是每兆瓦时的收入栏(poolPrice。5)xlim([5, 48.5])包含(“每个时期的每兆瓦时价格”)
在关闭之后开始发电机的成本是成本。此外,存在对当天的最大燃料使用量的约束。这种约束存在,因为您提前每天购买燃料,所以您只能使用您刚刚购买的内容。
您可以将调度问题作为二进制整数编程问题。定义索引一世
那j
,K.
,以及二进制调度向量y
,如下所示:
nperiods.
=时间段的数量,在本例中为48。
一世
=一个时间段,1 <=一世
<= 48。
j
=生成索引,1 <=j
在这个例子中<= 2。
Y(i,j,k)= 1
当时间一世
、发电机j
在功率水平上运行K.
.让低功率是k = 1
和高功率是k = 2
.发电机熄灭时y(i,j,k) = 0
.
确定发生在关闭后的生成器何时开始。为此,请定义辅助二进制变量Z(i,j)
这表明了是否充电打开发电机j
在一段时间内一世
.
z (i, j) = 1
当发电机j
在期间关闭一世
,但在一段时期I + 1
.z (i, j) = 0
除此以外。换句话说,z (i, j) = 1
什么时候y(i,j,k) = 0
和sum_k y(i + 1,j,k)= 1
.
你需要一种方法来设置Z.
自动根据设置y
.下面的线性约束处理此设置。
您还需要出现问题的参数,每个发电机的生成级别,发电机的消耗水平和可用燃料。
poolPrice(我)
——收入(单位:美元/兆瓦时一世
Gen(j,k)
- 发电机产生的MWj
在功率K.
燃料(J,K)
- 发电机使用的燃料j
在功率K.
totalFuel
- 一天内提供燃料
startCost
——发电机关机后启动的美元成本
fuelPrice
- 燃料单位的成本
你得到了poolprice.
当你执行时加载dispatchPrice;
.其他参数配置如下。
fuelPrice = 3;totalFuel = 3.95 e4;nPeriods =长度(poolPrice);% 48期ngens = 2;%两个发电机创= (61152;50150);%发电机1低= 61兆瓦,高= 152兆瓦燃料= (427806;325765);发电机2的%燃料消耗低= 325,高= 765startcost = 1e4;关闭发电机后启动发电机的成本
在两个操作点检查两个发电机的效率。
效率= /燃料将军;%计算每单位燃料使用的电量rr =效率';%的策划h =酒吧(rr);h(1)。FaceColor ='G';h(2)。FaceColor =“c”;传说(h,发电机1的那《发电机2》那“位置”那“东北朝”) ax = gca;斧子。XTick = [1, 2];斧子。XTickLabel = {“低”那'高的'};ylim([。1,.2])Ylabel('效率')
请注意,发电机2在其相应的操作点(低和高)处比发生器1更有效,但在其高工作点处的发生器1比在其低操作点处更有效。
要设置问题,您需要在问题表单中编码所有问题数据和约束。变量y(i,j,k)
代表问题的解决方案,以及辅助变量Z(i,j)
表示是否充电以打开发电机。y
是一个nperiods-by-ngens-by-2
数组,并Z.
是一个nperiods-by-ngens
数组中。所有变量都是二进制的。
y = Optimvar(“y”,nperiods,ngens,{“低”那'高的'},'类型'那'整数'那下界的,0,...'上行'1);z = optimvar (“z”,nperiods,ngens,'类型'那'整数'那下界的,0,...'上行'1);
为了确保功率电平没有超过一个等于1的组件,请设置线性不等式约束。
powercons = y(:,:,“低”)+ y(:,:,'高的') < = 1;
每期间的运行成本是该期间的燃料成本。为发电机j
在级别运营K.
,成本为Forclice *燃料(J,K)
.
创建一个表达式fuelUsed
占据所有燃料的账户。
yfuel = zeros(nperiods,ngens,2);yfuel(:,1,1)=燃料(1,1);%燃料在低设置中使用发电机1yfuel(:,1,2)=燃料(1,2);% 1号发电机在高调时的燃料使用yFuel(: 2 1) =燃料(2,1);%燃料在低设置中使用发电机2yFuel(: 2 2) =燃料(2,2);%燃料在高设置中使用发电机2燃料=总和(总和(y。* yfuel)));
约束是所用的燃料不仅仅是可用的燃料。
燃料=燃料<= totalfuel;
你怎么能得到求解器设置Z.
变量自动匹配匹配的活动/关闭期y
变量?回想一下,要满足的条件是z (i, j) = 1
什么时候y(i,j,k) = 0
和sum_k y(i + 1,j,k)= 1
.
请注意,sum_k( - y(i,j,k)+ y(i + 1,j,k))> 0
只要你愿意z (i, j) = 1
.
因此,包括在问题制定中的这些线性不等式约束。
sum_k( - y(i,j,k)+ y(i + 1,j,k)) - z(i,j)<= 0
.
另外,包括Z.
目标函数成本中的变量。与之Z.
目标函数中的变量,求解器试图降低它们的值,这意味着它试图将所有等于0。但是对于那些流行者打开时,对于那些间隔,线性不等式力Z(i,j)
等于1。
创建一个辅助变量W.
这代表着Y(i + 1,j,k) - y(i,j,k)
.代表发电机启动不等式W.
.
W = Optimexpr(nperiods,ngens);%分配wIdx = 1 :( nperiods-1);w(idx,:) = y(idx + 1,:,“低”) - y (idx:,“低”)+ Y(IDX + 1,:,'高的') - y (idx:,'高的');w(nperiods,:) = y(1,:,“低”) - Y(nperiods,:,“低”)+ y(1,:,'高的') - Y(nperiods,:,'高的');Switchcons = w - z <= 0;
目标函数包括运行发电机的燃料成本、运行发电机的收益和启动发电机的成本。
generatorlevel =零(尺寸(yfuel));generatorlevel(:,1,1)= gen(1,1);%填写水平GeneratorLevel(:,1,2)= Gen(1,2);GeneratorLevel(:,2,1)= Gen(2,1);GeneratorLevel(:,2,2)= Gen(2,2);
来收入= y。* GeneratorLevel。* PoolPrice
.
收入= optimexpr(大小(y));为了2 = 1: nPeriods收入(ii):,:) = poolPrice (ii) * y (ii):,:)。* generatorlevel (ii):,:);结尾
总燃料成本=fuelUsed * fuelPrice
.
fuelCost = fuelUsed * fuelPrice;
发电机启动成本=z * startcost.
.
startingCost z = * startCost;
利润=收入-
燃料总成本-
启动成本。
利润=总和(总和(收入))) - 燃料 - 总和(总和(起跑));
创建优化问题并包括目标和约束。
调度= optimproblem (“ObjectiveSense”那'最大化');dispatch.objective =利润;dispatch.constraints.switchcons = switchcons;dispatch.constraints.fuelcons =燃料;dispatch.constraints.powercons = Powercons;
要保存空间,请抑制迭代显示。
选项= Optimoptions(“intlinprog”那'展示'那'最终的');
解决这个问题。
[dispatchsol, fval exitflag、输出]=解决(调度,'选项',选项);
使用intlinprog解决问题。找到最优解。Intlinprog停止了,因为客观值是在间隙公差内的最优值,选项。AbsoluteGapTolerance = 0(默认值)intcon变量在tolerance, options中是整数。IntegerTolerance = 1e-05(默认值)。
将解决方案作为时间的函数绘制。
子图(3,1,1)栏(Dispatchsol.y(:,1,1)* Gen(1,1)+ Dispatchsol.y(:,1,2)* Gen(1,2),5,'G') xlim ([5, 48.5]) ylabel (“MWh”) 标题('发电机1最佳时间表'那'fontweight'那“大胆”)子图(3,1,2)栏(Dispatchsol.y(:,2,1)* Gen(1,1)+ Dispatchsol.y(:,2,2)* Gen(1,2),5,“c”) 标题(“发电机2最优调度”那'fontweight'那“大胆”) xlim ([5, 48.5]) ylabel (“MWh”) subplot(3,1,3) bar(poolPrice,.5) xlim([.5,48.5]) title('能源价格'那'fontweight'那“大胆”)包含(“时间”) ylabel ('$ / mwh')
发电机2比发电机1运行时间长,这是意料之中的,因为它更有效率。发电机2运行在其高功率水平,无论何时它是打开的。1号发电机主要以高功率运行,但在一次机组运行时下降到低功率。每个发电机每天运行一组连续的周期,因此,每天只产生一个启动成本。
检查这一点Z.
变量为1的时期,当发电机启动。
Starttimes = find(round(dispatchsol.z) == 1);%对非整数结果使用圆形结果[Period,TheGeNerator] = Ind2Sub(大小(Dispatchsol.z),starttifs)
theperiod =2×123日16
thegenerator =2×11 2
发电机开始匹配绘图时的时期。
如果指定较低的值startCost
,该解决方案涉及多个生成期。
startCost = 500;%选择用于启动发电机的较低罚款startingCost z = * startCost;利润= sum(sum(sum(revenue)) - fuelCost - sum(sum(start cost));dispatch.objective =利润;[dispatchsolnew, fvalnew exitflagnew outputnew] =解决(调度,'选项',选项);
使用intlinprog解决问题。找到最优解。Intlinprog停止了,因为客观值是在间隙公差内的最优值,选项。AbsoluteGapTolerance = 0(默认值)intcon变量在tolerance, options中是整数。IntegerTolerance = 1e-05(默认值)。
次要情节(1,1)栏(dispatchsolnew.y(:, 1, 1) *创(1,1)+ dispatchsolnew.y(:, 1, 2) *创(1、2),5,'G') xlim ([5, 48.5]) ylabel (“MWh”) 标题('发电机1最佳时间表'那'fontweight'那“大胆”次要情节(3、1、2)酒吧(dispatchsolnew.y(:, 2, 1) *创(1,1)+ dispatchsolnew.y(:, 2, 2) *创(1、2),5,“c”) 标题(“发电机2最优调度”那'fontweight'那“大胆”) xlim ([5, 48.5]) ylabel (“MWh”) subplot(3,1,3) bar(poolPrice,.5) xlim([.5,48.5]) title('能源价格'那'fontweight'那“大胆”)包含(“时间”) ylabel ('$ / mwh')
Starttimes = find(round(dispatchsolnews .z) == 1);%对非整数结果使用圆形结果[Period,TheGenerator] = Ind2Sub(大小(Dispatchsolnew.z),starttifs)
theperiod =3×122 16 45.
thegenerator =3×11 2 2