这个例子展示了如何最优地安排两台燃气发电机,这意味着获得最大的收入减去成本。虽然这个例子并不完全现实,但它确实说明了如何考虑依赖于决策时机的成本。
有关此问题的基于求解器的方法,请参见发电机的最优调度:基于求解器.
电力市场在一天的不同时段有不同的价格。如果你有发电机供电,你可以利用这种可变定价,在价格高的时候安排发电机运行。假设您控制两个生成器。每个发电机有三个功率等级(关、低、高)。每台发电机在每个功率级别都有一个指定的燃料消耗和功率生产速率。发电机关闭时燃料消耗为0。
您可以在一天中为每个半小时间隔(24小时,因此48个间隔)为每个发电机分配功率水平。根据历史记录,假设您知道在每个时间间隔内收到的每兆瓦时(MWh)收入。本例的数据来自澳大利亚能源市场运营商https://www.nemweb.com.au/REPORTS/CURRENT/
2013年年中,并在他们的术语下使用https: /
/
www。
aemo。
com。
非盟/
privacy-and-legal-notices /
copyright-permissions
.
负载dispatchPrice;获取poolPrice,即每兆瓦时的收益bar(poolPrice,.5) xlim([.5,48.5]) xlabel(“每个时期的每兆瓦时价格”)
发电机关闭后再启动是有成本的。此外,当天的最大燃料使用量也有限制。这个限制的存在是因为你提前一天买了燃料,所以你只能使用你刚买的燃料。
你可以把调度问题写成二进制整数规划问题。定义索引我
,j
,k
,和二进制调度向量y
,详情如下:
nPeriods
=时间周期的数量,在本例中为48。
我
=一个时间段,1 <=我
< = 48。
j
=生成器索引,1 <=j
本例中<= 2。
Y (i,j,k) = 1
当时间我
、发电机j
是否在功率水平运行k
.权力要低K = 1
,和高权力是K = 2
.发电机关闭时Sum_k y(i,j,k) = 0
.
确定发电机关闭后何时启动。为此,定义辅助二进制变量z (i, j)
指示是否为打开发电机而收费j
在期我
.
Z (i,j) = 1
当发电机j
周期为off我
,但偶尔会开I + 1
.Z (i,j) = 0
否则。换句话说,Z (i,j) = 1
当Sum_k y(i,j,k) = 0
而且Sum_k y(i+1,j,k) = 1
.
你需要一种方法来设置z
自动根据的设置y
.下面的线性约束处理此设置。
您还需要该问题的成本参数、每个发电机的发电水平、发电机的消耗水平和可用燃料。
poolPrice(我)
—收入,单位为美元/兆瓦时我
创(j, k)
——发电机产生的兆瓦j
在功率层面k
燃料(j, k)
——发电机使用的燃料j
在功率层面k
totalFuel
一天就能得到燃料
startCost
——关闭发电机后启动发电机的美元成本
fuelPrice
——单位燃料的成本
你有poolPrice
当你执行时加载dispatchPrice;
.其他参数配置如下。
燃料价格= 3;totalFuel = 3.95e4;nPeriods = length(poolPrice);% 48个周期nGens = 2;%两台发电机Gen = [61,152;50,150];%发电机1低= 61兆瓦,高= 152兆瓦燃料= [427,806;325,765];发电机2的燃料消耗%低= 325,高= 765startCost = 1e4;%发电机关闭后启动的成本
检查两台发电机在两个工作点的效率。
效率= gen /fuel;计算单位燃料耗电量Rr =效率';绘图百分比H = bar(rr);h(1)。FaceColor =‘g’;h(2)。FaceColor =“c”;传奇(h,发电机1的,《发电机2》,“位置”,“NorthEastOutside”) ax = gca;斧子。XTick = [1,2];斧子。XTickLabel = {“低”,“高”};ylim ([1, 2]) ylabel (“效率”)
请注意,发电机2在其相应的工作点(低和高)比发电机1更有效率,但发电机1在其高工作点比发电机2在其低工作点更有效率。
要设置问题,需要以问题的形式对所有问题数据和约束进行编码。的变量y (i, j, k)
表示问题的解和辅助变量z (i, j)
说明是否为打开发电机而收费。y
是一个nPeriods-by-nGens-by-2
数组,并z
是一个nPeriods-by-nGens
数组中。所有变量都是二进制的。
Y = optimvar(“y”nPeriods ngen, {“低”,“高”},“类型”,“整数”,下界的,0,...“UpperBound”1);Z = optimvar(“z”nPeriods ngen,“类型”,“整数”,下界的,0,...“UpperBound”1);
为了保证功率等级没有多于一个等于1的分量,可以设置线性不等式约束。
Powercons = y(:,:,“低”) + y(:,:,“高”) <= 1;
每段时间的运行成本是这段时间的燃料成本。为发电机j
水平运行k
,成本为燃料价格*燃料(j,k)
.
创建表达式fuelUsed
这就是所有的燃料消耗。
yFuel = 0 (nPeriods,nGens,2);yFuel(:,1,1) =燃料(1,1);发电机1在低设定时的燃料使用量yFuel(:,1,2) =燃料(1,2);发电机1在高设定时的燃料使用量yFuel(:,2,1) =燃料(2,1);发电机2在低设定时的燃料使用量yFuel(:,2,2) =燃料(2,2);发电机2在高设定时的燃料使用量fuelUsed = sum(sum(sum(y.*yFuel)));
限制条件是使用的燃料不能超过可用的燃料。
fuelcons = fuelUsed <= totalFuel;
如何让解算器设置z
变量的激活/关闭周期自动匹配y
变量?回想一下,要满足的条件是Z (i,j) = 1
什么时候Sum_k 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,:,“高”);开关= w - z <= 0;
目标函数包括运行发电机的燃料成本、运行发电机的收入和启动发电机的成本。
generatorlevel = 0 (size(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(size(y));为2 = 1: nPeriods收入(ii):,:) = poolPrice (ii) * y (ii):,:)。* generatorlevel (ii):,:);结束
总燃料成本=fuelUsed * fuelPrice
.
fuelCost = fuelUsed*fuelPrice;
发电机启动费用=z * startCost
.
startingCost = z*startCost;
利润=收入-
燃油总成本-
启动成本。
利润= sum(sum(sum(收入)))-燃料成本- sum(sum(startingCost));
创建一个优化问题,包括目标和约束条件。
调度=优化问题(“ObjectiveSense”,“最大化”);调度。目标=利润;dispatch.Constraints.switchcons = switchcons;dispatch.Constraints.fuelcons = fuelcons;dispatch.Constraints.powercons = powercons;
为了节省空间,抑制迭代显示。
选项= optimoptions(“intlinprog”,“显示”,“最后一次”);
解决问题。
[dispatchsol,fval,exitflag,output] = solve(dispatchsol,fval,exitflag,output)“选项”、选择);
使用intlinprog解决问题。找到最优解。Intlinprog停止是因为目标值在一个间隙公差的最优值,选项。AbsoluteGapTolerance = 0(默认值)。intcon变量是公差范围内的整数,选项。IntegerTolerance = 1e-05(默认值)。
把解画成时间的函数。
次要情节(1,1)栏(dispatchsol.y(:, 1, 1) *创(1,1)+ dispatchsol.y(:, 1, 2) *创(1、2),5,‘g’xlim([.5,48.5]) ylabel(“MWh”)标题(“发电机1最优计划”,“FontWeight”,“大胆”次要情节(3、1、2)酒吧(dispatchsol.y(:, 2, 1) *创(1,1)+ dispatchsol.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)
发电机2比发电机1运行时间长,这是你所期望的,因为它更有效率。发电机2无论何时开机都以高功率运行。发电机1主要运行在其高功率水平,但下降到低功率的一个时间单位。每个发电机每天运行一组连续的时间段,因此每天只产生一次启动成本。
检查z
变量为1,表示生成器启动时的周期。
Starttimes = find(round(dispatchsol.z) == 1);对于非整数结果使用round[theperiod,thegenerator] = ind2sub(size(dispatchsol.z),starttimes)
年度变化平均数低于=2×123日16
thegenerator =2×11 2
发电机启动的时间与图表相符。
的较低值startCost
,解决方案涉及多个生成周期。
startCost = 500;选择一个较低的惩罚启动发电机startingCost = z*startCost;利润= sum(sum(sum(收入)))-燃料成本- sum(sum(startingCost));调度。目标=利润;[dispatchsolnew,fvalnew,exitflagnew,outputnew] =求解(dispatchsolnew,fvalnew,exitflagnew,outputnew)“选项”、选择);
使用intlinprog解决问题。找到最优解。Intlinprog停止是因为目标值在一个间隙公差的最优值,选项。AbsoluteGapTolerance = 0(默认值)。intcon变量是公差范围内的整数,选项。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(dispatchsolnew.z) == 1);对于非整数结果使用round[theperiod,thegenerator] = ind2sub(size(dispatchsolnew.z),starttimes)
年度变化平均数低于=3×122 16 45
thegenerator =3×11 2 2