主要内容

发电机的最优调度:基于求解器

这个例子展示了如何最优地安排两台燃气发电机,这意味着获得最大的收入减去成本。虽然这个例子并不完全现实,但它确实说明了如何考虑依赖于决策时机的成本。

有关此问题的基于问题的方法,请参见发电机的最优调度:基于问题的

问题定义

电力市场在一天的不同时段有不同的价格。如果你有发电机,你可以利用这种可变定价,在价格高的时候安排发电机运行。假设有两个您控制的生成器。每个发电机有三个功率等级(关、低、高)。每台发电机在每个功率级别都有一个指定的燃料消耗和功率生产速率。当然,当发电机关闭时,燃料消耗为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(“每个时期的每兆瓦时价格”

图中包含一个轴对象。axis对象包含一个bar类型的对象。

发电机关闭后再启动是有成本的。另一个限制是一天的最大燃料使用量。最大燃料限制是因为你提前一天买了燃料,所以只能使用你刚买的燃料。

问题符号和参数

可以将调度问题表述为二进制整数规划问题,如下所示。定义索引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 + 1Z (i,j) = 0否则。换句话说,Z (i,j) = 1Sum_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 (“效率”

图中包含一个轴对象。axis对象包含2个bar类型的对象。这些对象表示生成器1和生成器2。

请注意,发电机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:nPeriodsjj = 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:nPeriodsjj = 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

图中包含3个轴对象。标题为Generator 1 optimal schedule的坐标轴对象1包含一个类型为bar的对象。标题为Generator 2 optimal schedule的Axes对象2包含一个类型为bar的对象。标题为Energy price的坐标轴对象3包含一个类型为bar的对象。

发电机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

图中包含3个轴对象。标题为Generator 1 optimal schedule的坐标轴对象1包含一个类型为bar的对象。标题为Generator 2 optimal schedule的Axes对象2包含一个类型为bar的对象。标题为Energy price的坐标轴对象3包含一个类型为bar的对象。

Starttimes = find(round(zsolutionnew) == 1);对于非整数结果使用round[theperiod,thegenerator] = ind2sub(size(zsolution),starttimes)
年度变化平均数低于=3×122 16 45
thegenerator =3×11 2 2

相关的话题