发电机的最优调度:基于求解器
这个例子展示了如何最优地安排两台燃气发电机,这意味着获得最大的收入减去成本。虽然这个例子并不完全现实,但它确实说明了如何考虑依赖于决策时机的成本。
有关此问题的基于问题的方法,请参见发电机的最优调度:基于问题的.
问题定义
电力市场在一天的不同时段有不同的价格。如果你有发电机,你可以利用这种可变定价,在价格高的时候安排发电机运行。假设有两个您控制的生成器。每个发电机有三个功率等级(关、低、高)。每台发电机在每个功率级别都有一个指定的燃料消耗和功率生产速率。当然,当发电机关闭时,燃料消耗为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) = 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;总燃料= 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在其低工作点更有效率。
解的变量
要设置问题,需要将所有问题数据和约束编码为intlinprog
解决需要。你有变量y (i, j, k)
表示问题的解,并且z (i, j)
充电启动发电机的辅助变量。y
是一个nPeriods-by-nGens-by-2
数组,并z
是一个nPeriods-by-nGens
数组中。
为了把这些变量放在一个长向量中,定义未知数变量x
:
X = [y(:);z(:)];
对于边界和线性约束,最容易使用的自然数组公式y
而且z
,然后将约束条件转换为总决策变量向量x
.
界限
解向量x
由二进制变量组成。设定边界磅
而且乌兰巴托
.
lby = 0 (nPeriods,nGens,2);y变量为% 0lbz = 0 (nPeriods,nGens);z变量为% 0Lb = [lby(:);lbz(:)];列向量下界Ub =个位(大小(lb));%二进制变量的下界为0,上界为1
线性约束条件
对于线性约束A*x <= b
的列数一个
矩阵必须与的长度相同x
等于的长度磅
.要创建一个
的大小,创建零个相同大小的矩阵y
而且z
矩阵。
cleary = 0 (nPeriods,nGens,2);clearz = 0 (nPeriods,nGens);
为了确保功率级别没有多于一个等于1的分量,可以设置一个线性不等式约束:
X (i,j,1) + X (i,j,2) <= 1
A = spalloc(nPeriods*nGens,长度(lb),2*nPeriods*nGens);% nPeriods*nGens不等式计数器= 1;为ii = 1:nPeriods为jj = 1:nGens temp = cleary;Temp (ii,jj,:) = 1;Addrow = [temp(:);clearz(:)]';A(counter,:) = sparse(addrow);计数器=计数器+ 1;结束结束b = ones(nPeriods*nGens,1);% A*x <= b表示x(i,j,1)和x(i,j,2)中只有一个等于1
每段时间的运行成本是这段时间的燃料成本。为发电机j
水平运行k
,成本为燃料价格*燃料(j,k)
.
为了确保发电机不会使用过多的燃料,在燃料使用的总和上创建一个不相等的约束。
yFuel = lby;初始化燃料使用数组yFuel(:,1,1) =燃料(1,1);发电机1在低设定时的燃料使用量yFuel(:,1,2) =燃料(1,2);发电机1在高设定时的燃料使用量yFuel(:,2,1) =燃料(2,1);发电机2在低设定时的燃料使用量yFuel(:,2,2) =燃料(2,2);发电机2在高设定时的燃料使用量addrow = [yFuel(:);clearz(:)]';A = [A;稀疏(addrow)];B = [B;总燃料];% A*x <= b表示总燃料使用量<=总燃料
设置发电机启动指示器变量
如何让解算器设置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
变量在目标函数中,求解器试图降低的值z
变量,这意味着它试图将它们都设为0。但是当发电机启动时,线性不等式迫使z (i, j)
等于1。
在线性不等式约束矩阵中添加额外的行一个
来表示这些新的不等式。对时间进行换行,使间隔1在逻辑上紧跟间隔48。
tempA = spalloc(nPeriods*nGens,长度(lb),2*nPeriods*nGens);计数器= 1;为ii = 1:nPeriods为jj = 1:nGens temp = cleary;Tempy = clearz;Temp (ii,jj,1) = -1;Temp (ii,jj,2) = -1;如果ii < nPeriods%间隔1 ~ 47Temp (ii+1,jj,1) = 1;Temp (ii+1,jj,2) = 1;其他的%间隔1紧跟在间隔48之后Temp (1,jj,1) = 1;Temp (1,jj,2) = 1;结束Tempy (ii,jj) = -1;Temp = [Temp (:);tempy(:)]';用于包含在tempA矩阵中的行向量tempA(counter,:) = sparse(temp);计数器=计数器+ 1;结束结束A = [A;tempA];b = [b; 0 (nPeriods*nGens,1)];% A*x <= b在发电机启动时设置z(i,j) = 1
约束的稀疏性
如果你有一个很大的问题,使用稀疏约束矩阵可以节省内存,也可以节省计算时间。约束矩阵一个
相当稀疏:
filledfraction = nnz(A)/numel(A)
填充分数= 0.0155
intlinprog
接受稀疏线性约束矩阵一个
而且Aeq
,但需要它们对应的向量约束b
而且说真的
吃饱。
定义目标
目标函数包括运行发电机的燃料成本、运行发电机的收入和启动发电机的成本。
Generatorlevel = lby;%生成,单位为MW,从0开始Generatorlevel (:,1,1) = gen(1,1);填写等级Generatorlevel (:,1,2) = gen(1,2);Generatorlevel (:,2,1) = gen(2,1);Generatorlevel (:,2,2) = gen(2,2);
收入=x。* generatorlevel。* poolPrice
收益=发电机级别;分配收益数组为ii = 1:nPeriods revenue(ii,:,:) = poolPrice(ii)*generatorlevel(ii,:,:);结束
总燃料成本=y。* yFuel * fuelPrice
燃料成本= yFuel*燃料价格;
启动费用=z。*的(大小(z)) * startCost
= (clearz + 1)*startCost;Starts = started (:);发电机启动成本向量
向量X = [y(:);z(:)]
.把总利润写成x
:
利润=收入-总燃料成本-启动成本
f = [revenue(:) - fuelCost(:);-starts];% f是目标函数向量
解决问题
为了节省空间,抑制迭代显示。
选项= optimoptions(“intlinprog”,“显示”,“最后一次”);[x, fval eflag、输出]= intlinprog (f, 1:长度(f), A, b,[],[],磅,乌兰巴托,选项);
找到最优解。Intlinprog停止是因为目标值在一个间隙公差的最优值,选项。RelativeGapTolerance = 0.0001(默认值)。intcon变量是公差范围内的整数,选项。IntegerTolerance = 1e-05(默认值)。
检查解决方案
检验解的最简单方法是除以解向量x
分成两部分,y
而且z
.
ysolution = x(1:nPeriods*nGens*2);zsolution = x(nPeriods*nGens*2+1:end);ysolution =重塑(ysolution,[nPeriods,nGens,2]);zsolution =重塑(zsolution,[nPeriods,nGens]);
把解画成时间的函数。
次要情节(1,1)栏(ysolution(:, 1, 1) *创(1,1)+ ysolution(:, 1, 2) *创(1、2),5,‘g’xlim([.5,48.5]) ylabel(“MWh”)标题(“发电机1最优计划”,“FontWeight”,“大胆”次要情节(3、1、2)酒吧(ysolution(:, 2, 1) *(2, 1)一代+ ysolution(:, 2, 2) *创(2,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(zsolution) == 1);对于非整数结果使用round[theperiod,thegenerator] = ind2sub(size(zsolution),starttimes)
年度变化平均数低于=2×123日16
thegenerator =2×11 2
发电机启动的时间与图表相符。
与较低的启动惩罚相比
如果你选择一个小的值startCost
,解决方案涉及多个生成周期。
startCost = 500;选择一个较低的惩罚启动发电机= (clearz + 1)*startCost;Starts = started (:);起始成本向量fnew = [revenue(:) - fuelCost(:);-starts];新目标函数[xnew, fvalnew eflagnew outputnew] =…intlinprog (-fnew 1:长度(fnew), A, b,[],[],磅,乌兰巴托,选项);
找到最优解。Intlinprog停止是因为目标值在一个间隙公差的最优值,选项。RelativeGapTolerance = 0.0001(默认值)。intcon变量是公差范围内的整数,选项。IntegerTolerance = 1e-05(默认值)。
ysolutionnew = xnew(1:nPeriods*nGens*2);zsolutionnew = xnew(nPeriods*nGens*2+1:end);ysolutionnew =重塑(ysolutionnew,[nPeriods,nGens,2]);zsolutionnew =重塑(zsolutionnew,[nPeriods,nGens]);次要情节(1,1)栏(ysolutionnew(:, 1, 1) *创(1,1)+ ysolutionnew(:, 1, 2) *创(1、2),5,‘g’xlim([.5,48.5]) ylabel(“MWh”)标题(“发电机1最优计划”,“FontWeight”,“大胆”次要情节(3、1、2)酒吧(ysolutionnew(:, 2, 1) *(2, 1)一代+ ysolutionnew(:, 2, 2) *创(2,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(zsolutionnew) == 1);对于非整数结果使用round[theperiod,thegenerator] = ind2sub(size(zsolution),starttimes)
年度变化平均数低于=3×122 16 45
thegenerator =3×11 2 2