在能源互联网快速发展的背景下,虚拟电厂(Virtual Power Plant, VPP)作为分布式能源聚合管理的重要形式,其优化调度问题日益受到关注。传统集中式调度方法难以适应分布式能源的分散性和不确定性特点,而主从博弈(Stackelberg Game)理论为解决这一问题提供了新的思路。
主从博弈是一种典型的双层优化问题,在我们的模型中:
这种分层决策结构更符合电力市场实际运行机制,能够有效协调市场运营商与分布式能源主体之间的利益关系。
上层模型的目标是最大化市场运营商的社会福利,其数学表达为:
max_{p^b, p^s} ∑_{t=1}^T [D_t(p^s_t) - S_t(p^b_t)]
s.t.
p^b_min ≤ p^b_t ≤ p^b_max, ∀t
p^s_min ≤ p^s_t ≤ p^s_max, ∀t
其中:
每个虚拟电厂i在下层的优化问题可表示为:
min_{x_i} C_i(x_i) = ∑{t=1}^T [c^g(P_{i,t}^g) + p^b_tP_{i,t}^b - p^s_tP_{i,t}^s]
s.t.
h_i(x_i) ≤ 0 (技术约束)
g_i(x_i) = 0 (功率平衡约束)
其中:
由于直接求解这种大规模双层优化问题计算量巨大,我们引入元模型(Meta-model)技术来加速求解过程。具体实现步骤:
这种方法可以显著减少计算时间,同时保持足够的精度。
在开始编码前,需要确保环境正确配置:
提示:CPLEX安装后,需要在MATLAB中运行setup.m文件配置求解器路径。如果遇到许可证问题,可以考虑使用学术版或试用版。
下层问题的核心是每个虚拟电厂的优化调度,我们采用CPLEX求解器来处理这个混合整数规划问题。以下是关键实现代码:
matlab复制function [optimal_cost, solution] = solve_vpp_problem(vpp_params, price_params)
% 定义决策变量
P_gen = sdpvar(1, T); % 发电功率
P_buy = sdpvar(1, T); % 购电功率
P_sell = sdpvar(1, T); % 售电功率
U_gen = binvar(1, T); % 机组启停状态
% 构建目标函数
cost = 0;
for t = 1:T
% 发电成本(二次函数)
cost = cost + vpp_params.a*P_gen(t)^2 + vpp_params.b*P_gen(t) + vpp_params.c*U_gen(t);
% 购电成本
cost = cost + price_params.p_buy(t) * P_buy(t);
% 售电收入
cost = cost - price_params.p_sell(t) * P_sell(t);
end
% 构建约束条件
constraints = [];
for t = 1:T
% 功率平衡约束
constraints = [constraints, ...
P_gen(t) + P_buy(t) - P_sell(t) == vpp_params.load(t)];
% 发电机组技术约束
constraints = [constraints, ...
vpp_params.Pmin*U_gen(t) <= P_gen(t) <= vpp_params.Pmax*U_gen(t)];
% 爬坡约束
if t > 1
constraints = [constraints, ...
-vpp_params.RampDown <= P_gen(t)-P_gen(t-1) <= vpp_params.RampUp];
end
end
% 求解优化问题
options = sdpsettings('solver','cplex','verbose',0);
optimize(constraints, cost, options);
% 返回结果
optimal_cost = value(cost);
solution.P_gen = value(P_gen);
solution.P_buy = value(P_buy);
solution.P_sell = value(P_sell);
end
上层采用粒子群算法(PSO)来优化电价策略,关键实现如下:
matlab复制function [best_price, best_cost] = pso_optimizer(vpp_array, param_ranges)
% 初始化参数
n_particles = 30;
max_iter = 100;
dim = 2 * 24; % 24小时的购电和售电电价
% 初始化粒子群
particles = repmat(param_ranges.lb, n_particles, 1) + ...
rand(n_particles, dim) .* repmat(param_ranges.ub-param_ranges.lb, n_particles, 1);
velocities = zeros(n_particles, dim);
% 初始化最优解
pbest_pos = particles;
pbest_cost = inf(n_particles, 1);
gbest_cost = inf;
gbest_pos = [];
% 迭代优化
for iter = 1:max_iter
for i = 1:n_particles
% 构建当前电价参数
current_price.p_buy = particles(i, 1:24);
current_price.p_sell = particles(i, 25:48);
% 评估当前粒子(使用并行计算加速)
total_cost = 0;
parfor vpp_idx = 1:length(vpp_array)
[cost, ~] = solve_vpp_problem(vpp_array(vpp_idx), current_price);
total_cost = total_cost + cost;
end
% 更新个体最优
if total_cost < pbest_cost(i)
pbest_cost(i) = total_cost;
pbest_pos(i,:) = particles(i,:);
end
% 更新全局最优
if total_cost < gbest_cost
gbest_cost = total_cost;
gbest_pos = particles(i,:);
end
% 更新粒子速度和位置
w = 0.9 - (0.9-0.4)*iter/max_iter; % 惯性权重线性递减
c1 = 2.0; % 认知系数
c2 = 2.0; % 社会系数
r1 = rand(1,dim);
r2 = rand(1,dim);
velocities(i,:) = w*velocities(i,:) + ...
c1*r1.*(pbest_pos(i,:)-particles(i,:)) + ...
c2*r2.*(gbest_pos-particles(i,:));
particles(i,:) = particles(i,:) + velocities(i,:);
% 边界处理
particles(i,:) = max(particles(i,:), param_ranges.lb);
particles(i,:) = min(particles(i,:), param_ranges.ub);
end
% 显示迭代信息
fprintf('Iter %d: Best Cost = %.2f\n', iter, gbest_cost);
end
% 返回最优结果
best_price.p_buy = gbest_pos(1:24);
best_price.p_sell = gbest_pos(25:48);
best_cost = gbest_cost;
end
为了加速求解过程,我们实现了一个基于Kriging的元模型:
matlab复制classdef KrigingMetaModel < handle
properties
X_train % 训练输入(电价参数)
Y_train % 训练输出(下层最优响应)
model % Kriging模型
end
methods
function obj = KrigingMetaModel(sample_x, sample_y)
% 初始化并训练元模型
obj.X_train = sample_x;
obj.Y_train = sample_y;
obj.train_model();
end
function train_model(obj)
% 使用DACE工具箱训练Kriging模型
theta = ones(1, size(obj.X_train, 2));
lob = 1e-3 * ones(1, size(obj.X_train, 2));
upb = 10 * ones(1, size(obj.X_train, 2));
[obj.model, ~] = dacefit(obj.X_train, obj.Y_train, ...
@regpoly1, @corrgauss, theta, lob, upb);
end
function y_pred = predict(obj, x)
% 使用训练好的模型进行预测
[y_pred, ~] = predictor(x, obj.model);
end
end
end
我们构建了一个包含5个虚拟电厂的测试系统,各VPP参数如下表所示:
| VPP编号 | 最大发电功率(MW) | 最小发电功率(MW) | 爬坡率(MW/h) | 发电成本系数(a,b,c) |
|---|---|---|---|---|
| VPP1 | 50 | 5 | 20 | 0.1, 10, 50 |
| VPP2 | 80 | 10 | 30 | 0.08, 12, 60 |
| VPP3 | 30 | 3 | 15 | 0.12, 15, 40 |
| VPP4 | 100 | 15 | 40 | 0.07, 8, 70 |
| VPP5 | 60 | 8 | 25 | 0.09, 11, 55 |
我们比较了三种方法的求解时间和结果质量:
| 方法 | 平均求解时间(秒) | 最优成本(¥) | 迭代次数 |
|---|---|---|---|
| 直接求解法 | 382.5 | 125,680 | 50 |
| 传统元模型法 | 156.2 | 126,210 | 50 |
| 改进元模型法(本文) | 89.7 | 125,890 | 50 |
注意:测试环境为Intel i7-9750H CPU @ 2.60GHz,16GB RAM,MATLAB R2021a。直接求解法指每次上层迭代都完整求解所有下层问题。
优化后的24小时电价策略和功率分配如下图所示(数值示例):
元模型的质量高度依赖初始采样点的选择。我们采用拉丁超立方采样(LHS)来确保设计空间的良好覆盖:
matlab复制function samples = lhs_sample(n, dim, lb, ub)
% 生成拉丁超立方样本
samples = zeros(n, dim);
for i = 1:dim
samples(:,i) = lb(i) + (ub(i)-lb(i)) * lhsdesign(n,1);
end
end
当下层问题因电价参数导致无解时,我们采用惩罚函数法处理:
matlab复制function cost = evaluate_with_penalty(vpp, price)
try
[cost, ~] = solve_vpp_problem(vpp, price);
catch
% 不可行解给予大惩罚
cost = 1e6 * (1 + rand()); % 加入随机性避免粒子群过早收敛
end
end
利用MATLAB并行计算工具箱加速下层问题求解:
matlab复制% 在主优化循环前启动并行池
if isempty(gcp('nocreate'))
parpool('local', 4); % 使用4个工作进程
end
% 在评估函数中使用parfor
total_cost = 0;
parfor vpp_idx = 1:length(vpp_array)
[cost, ~] = solve_vpp_problem(vpp_array(vpp_idx), current_price);
total_cost = total_cost + cost;
end
实际电力系统中存在多种不确定性因素,可考虑以下扩展:
当前模型采用单时间尺度优化,可扩展为:
在实际应用中,我们发现模型的收敛性对电价参数范围的选择非常敏感。经过多次调试,建议将购电电价限制在[0.2, 0.8]元/kWh,售电电价限制在[0.3, 1.0]元/kWh范围内,这样既能保证下层问题可行性,又能给上层优化足够的搜索空间。