MATLAB考虑源荷不确定性的电力系统优化

一、源荷不确定性建模方法综述

在电力系统优化中,源(可再生能源出力)和荷(负荷需求)的不确定性是核心挑战。以下是主要建模方法:

方法 原理 优点 缺点 适用场景
确定性优化 使用预测均值 简单,计算快 忽略不确定性,结果保守 不确定性小,要求不高的场景
随机规划 基于概率分布,多场景 考虑多种可能,期望最优 场景数多时计算量大 可再生能源高渗透
鲁棒优化 最坏情况下最优 保证可行,抗干扰强 结果保守 安全要求高的场景
机会约束规划 允许小概率违反约束 平衡经济性与可靠性 求解复杂 可接受一定风险的场景
分布鲁棒优化 结合随机和鲁棒 平衡保守性和经济性 建模求解复杂 不确定性信息有限

本文将重点介绍基于场景的随机规划鲁棒优化两种主流方法。


二、场景生成与削减技术

2.1 不确定性源建模

matlab 复制代码
%% 1. 风电、光伏、负荷不确定性建模
clear; clc; close all;

%% 1.1 参数设置
n_hours = 24;               % 24小时调度
n_scenarios = 100;          % 初始场景数
n_clusters = 10;            % 削减后场景数
time = 1:n_hours;

%% 1.2 风电出力不确定性建模
% 均值曲线 (典型日)
wind_mean = 50 + 20 * sin(2*pi*(time-6)/24);  % MW

% 标准差 (白天波动大)
wind_std = 0.2 * wind_mean;  % 20%的波动

% 生成场景 (正态分布)
wind_scenarios = zeros(n_scenarios, n_hours);
for h = 1:n_hours
    wind_scenarios(:, h) = wind_mean(h) + wind_std(h) * randn(n_scenarios, 1);
    % 截断在[0, 最大容量]之间
    wind_scenarios(:, h) = max(0, min(wind_scenarios(:, h), 100));
end

%% 1.3 光伏出力不确定性建模
pv_mean = 60 * sin(pi*(time-6)/12);  % 白天出力
pv_mean(pv_mean < 0) = 0;

pv_std = 0.15 * pv_mean;
pv_std(isnan(pv_std)) = 0.1;  % 处理夜晚0出力的标准差

pv_scenarios = zeros(n_scenarios, n_hours);
for h = 1:n_hours
    if pv_mean(h) > 0
        pv_scenarios(:, h) = pv_mean(h) + pv_std(h) * randn(n_scenarios, 1);
        pv_scenarios(:, h) = max(0, min(pv_scenarios(:, h), 80));
    end
end

%% 1.4 负荷不确定性建模
load_mean = 150 + 50 * sin(2*pi*(time-14)/24);  % MW
load_std = 0.1 * load_mean;

load_scenarios = zeros(n_scenarios, n_hours);
for h = 1:n_hours
    load_scenarios(:, h) = load_mean(h) + load_std(h) * randn(n_scenarios, 1);
    load_scenarios(:, h) = max(100, load_scenarios(:, h));  % 最小负荷
end

%% 1.5 场景概率 (初始等概率)
prob_init = ones(n_scenarios, 1) / n_scenarios;

%% 2. 场景削减 (基于K-means聚类)
function [scenarios_red, prob_red, idx] = scenario_reduction(original_scenarios, original_prob, n_clusters)
    % 输入:
    %   original_scenarios: n_scenarios × n_hours 矩阵
    %   original_prob: n_scenarios × 1 概率向量
    %   n_clusters: 削减后场景数
    % 输出:
    %   scenarios_red: n_clusters × n_hours 削减后场景
    %   prob_red: n_clusters × 1 削减后概率
    %   idx: 每个原始场景所属的聚类
    
    [n_scenarios, n_hours] = size(original_scenarios);
    
    % 使用K-means聚类
    [idx, C] = kmeans(original_scenarios, n_clusters, ...
        'MaxIter', 1000, 'Replicates', 10);
    
    scenarios_red = C;
    
    % 计算每个聚类的概率
    prob_red = zeros(n_clusters, 1);
    for k = 1:n_clusters
        cluster_members = (idx == k);
        prob_red(k) = sum(original_prob(cluster_members));
    end
    
    % 可视化聚类结果
    figure;
    for k = 1:min(4, n_clusters)
        subplot(2,2,k);
        cluster_data = original_scenarios(idx == k, :);
        plot(time, cluster_data', 'Color', [0.8, 0.8, 0.8], 'LineWidth', 0.5);
        hold on;
        plot(time, scenarios_red(k, :), 'r-', 'LineWidth', 2);
        title(sprintf('Cluster %d (Prob=%.3f)', k, prob_red(k)));
        xlabel('Hour');
        ylabel('Value');
        grid on;
    end
end

% 应用场景削减
[wind_red, prob_wind, idx_wind] = scenario_reduction(wind_scenarios, prob_init, n_clusters);
[pv_red, prob_pv, idx_pv] = scenario_reduction(pv_scenarios, prob_init, n_clusters);
[load_red, prob_load, idx_load] = scenario_reduction(load_scenarios, prob_init, n_clusters);

%% 3. 联合场景生成 (考虑相关性)
function [joint_scenarios, joint_prob] = generate_joint_scenarios(...
    wind_scenarios, prob_wind, pv_scenarios, prob_pv, load_scenarios, prob_load)
    
    n_wind = size(wind_scenarios, 1);
    n_pv = size(pv_scenarios, 1);
    n_load = size(load_scenarios, 1);
    
    % 假设独立,生成所有组合
    n_joint = n_wind * n_pv * n_load;
    joint_scenarios = zeros(n_joint, 3, 24);  % 维度: 场景 × 3个变量 × 24小时
    joint_prob = zeros(n_joint, 1);
    
    idx = 1;
    for i = 1:n_wind
        for j = 1:n_pv
            for k = 1:n_load
                joint_scenarios(idx, 1, :) = wind_scenarios(i, :);
                joint_scenarios(idx, 2, :) = pv_scenarios(j, :);
                joint_scenarios(idx, 3, :) = load_scenarios(k, :);
                joint_prob(idx) = prob_wind(i) * prob_pv(j) * prob_load(k);
                idx = idx + 1;
            end
        end
    end
    
    % 进一步削减联合场景
    % 将三维数据展平为二维
    joint_scenarios_flat = reshape(joint_scenarios, n_joint, []);
    [joint_scenarios_red, joint_prob_red] = scenario_reduction(...
        joint_scenarios_flat, joint_prob, 20);
    
    % 恢复为三维
    joint_scenarios = reshape(joint_scenarios_red, [], 3, 24);
    joint_prob = joint_prob_red;
end

% 生成联合场景
[joint_scenarios, joint_prob] = generate_joint_scenarios(...
    wind_red, prob_wind, pv_red, prob_pv, load_red, prob_load);

n_joint = size(joint_scenarios, 1);
fprintf('削减后联合场景数: %d\n', n_joint);

三、基于场景的随机规划模型

3.1 两阶段随机规划模型

matlab 复制代码
%% 两阶段随机规划:考虑源荷不确定性的电力系统调度
clear; clc;

%% 1. 系统参数
n_hours = 24;
n_units = 3;        % 常规机组数
n_wind = 1;         % 风电场数
n_pv = 1;           % 光伏电站数
n_scenarios = size(joint_scenarios, 1);  % 场景数

%% 2. 机组参数
% 机组1: 基荷机组
units(1).P_min = 50;     % MW
units(1).P_max = 200;    % MW
units(1).a = 0.01;       % 成本系数 a ($/MW^2)
units(1).b = 20;         % 成本系数 b ($/MW)
units(1).c = 100;        % 成本系数 c ($)
units(1).ramp_up = 100;  % MW/h
units(1).ramp_down = 100; % MW/h
units(1).min_up = 4;     % 最小开机时间 (h)
units(1).min_down = 4;   % 最小停机时间 (h)
units(1).startup_cost = 500;  % 启动成本 ($)
units(1).shutdown_cost = 100; % 停机成本 ($)

% 机组2: 腰荷机组
units(2).P_min = 20;
units(2).P_max = 100;
units(2).a = 0.02;
units(2).b = 30;
units(2).c = 50;
units(2).ramp_up = 80;
units(2).ramp_down = 80;
units(2).min_up = 2;
units(2).min_down = 2;
units(2).startup_cost = 300;
units(2).shutdown_cost = 50;

% 机组3: 峰荷机组
units(3).P_min = 0;
units(3).P_max = 50;
units(3).a = 0.05;
units(3).b = 50;
units(3).c = 0;
units(3).ramp_up = 50;
units(3).ramp_down = 50;
units(3).min_up = 1;
units(3).min_down = 1;
units(3).startup_cost = 200;
units(3).shutdown_cost = 0;

%% 3. 可再生能源参数
% 弃风/弃光惩罚
wind_penalty = 50;  % $/MWh
pv_penalty = 40;    % $/MWh

% 旋转备用要求
spinning_reserve = 0.1;  % 10%的负荷作为旋转备用

%% 4. 构建两阶段随机规划模型
% 第一阶段变量: 机组启停状态 (二进制)
% 第二阶段变量: 机组出力、可再生能源实际出力、弃风弃光量 (连续)

% 使用YALMIP建模
addpath(genpath('yalmip'));  % 添加YALMIP路径
addpath(genpath('gurobi'));  % 添加Gurobi路径 (或其他求解器)

% 决策变量
u = binvar(n_units, n_hours, 'full');      % 机组启停状态
v = binvar(n_units, n_hours, 'full');      % 启动状态
w = binvar(n_units, n_hours, 'full');      % 停机状态

% 第二阶段变量 (场景相关)
P = sdpvar(n_units, n_hours, n_scenarios, 'full');  % 机组出力
P_wind_actual = sdpvar(n_hours, n_scenarios, 'full');  % 风电实际出力
P_pv_actual = sdpvar(n_hours, n_scenarios, 'full');    % 光伏实际出力
wind_curtail = sdpvar(n_hours, n_scenarios, 'full');   % 弃风量
pv_curtail = sdpvar(n_hours, n_scenarios, 'full');     % 弃光量

%% 5. 目标函数: 最小化期望总成本
total_cost = 0;

% 第一阶段成本: 启停成本
for i = 1:n_units
    for t = 1:n_hours
        total_cost = total_cost + units(i).startup_cost * v(i,t) + ...
                     units(i).shutdown_cost * w(i,t);
    end
end

% 第二阶段成本期望值
for s = 1:n_scenarios
    scenario_prob = joint_prob(s);
    
    for t = 1:n_hours
        % 从联合场景中获取数据
        wind_available = joint_scenarios(s, 1, t);
        pv_available = joint_scenarios(s, 2, t);
        load_demand = joint_scenarios(s, 3, t);
        
        % 发电成本
        for i = 1:n_units
            total_cost = total_cost + scenario_prob * (...
                units(i).a * P(i,t,s)^2 + ...
                units(i).b * P(i,t,s) + ...
                units(i).c * u(i,t));
        end
        
        % 弃风弃光惩罚
        total_cost = total_cost + scenario_prob * (...
            wind_penalty * wind_curtail(t,s) + ...
            pv_penalty * pv_curtail(t,s));
    end
end

%% 6. 约束条件
constraints = [];

% 6.1 启停逻辑约束
for i = 1:n_units
    for t = 1:n_hours
        % 启动和停机指示器
        if t > 1
            constraints = [constraints, v(i,t) >= u(i,t) - u(i,t-1)];
            constraints = [constraints, w(i,t) >= u(i,t-1) - u(i,t)];
        else
            constraints = [constraints, v(i,1) >= u(i,1) - 0];  % 初始状态假设为0
            constraints = [constraints, w(i,1) >= 0 - u(i,1)];
        end
        
        constraints = [constraints, v(i,t) <= u(i,t)];
        constraints = [constraints, w(i,t) <= 1 - u(i,t)];
        constraints = [constraints, v(i,t) + w(i,t) <= 1];
    end
end

% 6.2 最小启停时间约束
for i = 1:n_units
    for t = 1:n_hours
        % 最小开机时间
        if t + units(i).min_up - 1 <= n_hours
            constraints = [constraints, ...
                sum(u(i, t:min(t+units(i).min_up-1, n_hours))) >= ...
                units(i).min_up * v(i,t)];
        end
        
        % 最小停机时间
        if t + units(i).min_down - 1 <= n_hours
            constraints = [constraints, ...
                sum(1 - u(i, t:min(t+units(i).min_down-1, n_hours))) >= ...
                units(i).min_down * w(i,t)];
        end
    end
end

% 6.3 场景相关的约束
for s = 1:n_scenarios
    for t = 1:n_hours
        % 从联合场景中获取数据
        wind_available = joint_scenarios(s, 1, t);
        pv_available = joint_scenarios(s, 2, t);
        load_demand = joint_scenarios(s, 3, t);
        
        % 功率平衡约束
        total_gen = sum(P(:,t,s)) + P_wind_actual(t,s) + P_pv_actual(t,s);
        constraints = [constraints, total_gen == load_demand];
        
        % 机组出力上下限约束
        for i = 1:n_units
            constraints = [constraints, ...
                units(i).P_min * u(i,t) <= P(i,t,s) <= units(i).P_max * u(i,t)];
        end
        
        % 爬坡约束
        if t > 1
            for i = 1:n_units
                constraints = [constraints, ...
                    P(i,t,s) - P(i,t-1,s) <= units(i).ramp_up];
                constraints = [constraints, ...
                    P(i,t-1,s) - P(i,t,s) <= units(i).ramp_down];
            end
        end
        
        % 可再生能源出力约束
        constraints = [constraints, 0 <= P_wind_actual(t,s) <= wind_available];
        constraints = [constraints, 0 <= P_pv_actual(t,s) <= pv_available];
        
        % 弃风弃光定义
        constraints = [constraints, ...
            wind_curtail(t,s) == wind_available - P_wind_actual(t,s)];
        constraints = [constraints, ...
            pv_curtail(t,s) == pv_available - P_pv_actual(t,s)];
        
        % 旋转备用约束
        quick_reserve = 0;
        for i = 1:n_units
            quick_reserve = quick_reserve + min(units(i).ramp_up, ...
                units(i).P_max * u(i,t) - P(i,t,s));
        end
        constraints = [constraints, quick_reserve >= spinning_reserve * load_demand];
    end
end

%% 7. 求解优化问题
ops = sdpsettings('solver', 'gurobi', 'verbose', 1, 'showprogress', 1);
ops.gurobi.TimeLimit = 3600;  % 1小时时间限制
ops.gurobi.MIPGap = 0.01;     % 1%的MIP间隙

% 求解
tic;
diagnostics = optimize(constraints, total_cost, ops);
solve_time = toc;

if diagnostics.problem == 0
    disp('=== 求解成功 ===');
    fprintf('求解时间: %.2f 秒\n', solve_time);
    fprintf('目标函数值: %.2f $\n', value(total_cost));
    
    % 提取结果
    u_opt = value(u);
    P_opt = value(P);
    P_wind_opt = value(P_wind_actual);
    P_pv_opt = value(P_pv_actual);
    wind_curtail_opt = value(wind_curtail);
    pv_curtail_opt = value(pv_curtail);
    
    % 计算期望值
    P_expected = zeros(n_units, n_hours);
    for i = 1:n_units
        for t = 1:n_hours
            for s = 1:n_scenarios
                P_expected(i,t) = P_expected(i,t) + joint_prob(s) * P_opt(i,t,s);
            end
        end
    end
    
else
    disp('求解失败');
    disp(yalmiperror(diagnostics.problem));
end

%% 8. 结果可视化
plot_results(u_opt, P_expected, P_wind_opt, P_pv_opt, ...
    wind_curtail_opt, pv_curtail_opt, joint_scenarios, joint_prob);

3.2 结果可视化函数

matlab 复制代码
function plot_results(u_opt, P_expected, P_wind_opt, P_pv_opt, ...
    wind_curtail_opt, pv_curtail_opt, joint_scenarios, joint_prob)
    
    [n_units, n_hours] = size(P_expected);
    n_scenarios = size(joint_scenarios, 1);
    time = 1:n_hours;
    
    figure('Position', [100, 100, 1400, 900]);
    
    % 子图1: 机组启停状态
    subplot(3,3,1);
    imagesc(time, 1:n_units, u_opt);
    colormap(flipud(gray));
    colorbar;
    xlabel('时间 (小时)');
    ylabel('机组编号');
    title('机组启停状态');
    set(gca, 'YTick', 1:n_units);
    
    % 子图2: 期望出力
    subplot(3,3,2);
    area_plot = area(time, P_expected');
    legend('机组1', '机组2', '机组3', 'Location', 'best');
    xlabel('时间 (小时)');
    ylabel('出力 (MW)');
    title('机组期望出力');
    grid on;
    
    % 子图3: 可再生能源出力
    subplot(3,3,3);
    hold on;
    
    % 计算期望的可再生能源出力
    P_wind_expected = zeros(1, n_hours);
    P_pv_expected = zeros(1, n_hours);
    for t = 1:n_hours
        for s = 1:n_scenarios
            P_wind_expected(t) = P_wind_expected(t) + joint_prob(s) * P_wind_opt(t,s);
            P_pv_expected(t) = P_pv_expected(t) + joint_prob(s) * P_pv_opt(t,s);
        end
    end
    
    plot(time, P_wind_expected, 'b-', 'LineWidth', 2, 'DisplayName', '风电期望出力');
    plot(time, P_pv_expected, 'g-', 'LineWidth', 2, 'DisplayName', '光伏期望出力');
    
    % 计算可用可再生能源
    wind_available_exp = zeros(1, n_hours);
    pv_available_exp = zeros(1, n_hours);
    for t = 1:n_hours
        for s = 1:n_scenarios
            wind_available_exp(t) = wind_available_exp(t) + joint_prob(s) * joint_scenarios(s,1,t);
            pv_available_exp(t) = pv_available_exp(t) + joint_prob(s) * joint_scenarios(s,2,t);
        end
    end
    
    plot(time, wind_available_exp, 'b--', 'LineWidth', 1, 'DisplayName', '风电可用');
    plot(time, pv_available_exp, 'g--', 'LineWidth', 1, 'DisplayName', '光伏可用');
    
    xlabel('时间 (小时)');
    ylabel('出力 (MW)');
    title('可再生能源出力');
    legend('Location', 'best');
    grid on;
    
    % 子图4: 弃风弃光
    subplot(3,3,4);
    wind_curtail_exp = zeros(1, n_hours);
    pv_curtail_exp = zeros(1, n_hours);
    for t = 1:n_hours
        for s = 1:n_scenarios
            wind_curtail_exp(t) = wind_curtail_exp(t) + joint_prob(s) * wind_curtail_opt(t,s);
            pv_curtail_exp(t) = pv_curtail_exp(t) + joint_prob(s) * pv_curtail_opt(t,s);
        end
    end
    
    bar_data = [wind_curtail_exp; pv_curtail_exp]';
    bar(time, bar_data, 'stacked');
    xlabel('时间 (小时)');
    ylabel('弃电量 (MWh)');
    title('弃风弃光量');
    legend('弃风', '弃光', 'Location', 'best');
    grid on;
    
    % 子图5: 成本分解
    subplot(3,3,5);
    % 计算各项成本
    fuel_cost = 0;
    startup_cost = 0;
    shutdown_cost = 0;
    curtail_cost = 0;
    
    % 这里需要从优化结果中计算具体成本
    % 简化显示
    cost_labels = {'燃料成本', '启停成本', '弃电惩罚'};
    cost_values = [70, 15, 5];  % 示例值,单位: 千美元
    bar(cost_values);
    set(gca, 'XTickLabel', cost_labels);
    ylabel('成本 (千$)');
    title('成本分解');
    grid on;
    
    % 子图6: 典型场景下的功率平衡
    subplot(3,3,6);
    % 选择概率最大的场景
    [~, max_prob_idx] = max(joint_prob);
    
    load_scenario = squeeze(joint_scenarios(max_prob_idx, 3, :))';
    total_gen = sum(P_opt(:,:,max_prob_idx), 1) + ...
                P_wind_opt(:,max_prob_idx)' + P_pv_opt(:,max_prob_idx)';
    
    area_plot = area(time, [P_opt(:,:,max_prob_idx)', ...
                           P_wind_opt(:,max_prob_idx)', ...
                           P_pv_opt(:,max_prob_idx)']);
    hold on;
    plot(time, load_scenario, 'k-', 'LineWidth', 2, 'DisplayName', '负荷');
    xlabel('时间 (小时)');
    ylabel('功率 (MW)');
    title('典型场景功率平衡');
    legend('机组1', '机组2', '机组3', '风电', '光伏', '负荷', 'Location', 'best');
    grid on;
    
    % 子图7: 备用充足性
    subplot(3,3,7);
    reserve_available = zeros(1, n_hours);
    reserve_required = zeros(1, n_hours);
    
    for t = 1:n_hours
        load_exp = 0;
        for s = 1:n_scenarios
            load_exp = load_exp + joint_prob(s) * joint_scenarios(s,3,t);
        end
        reserve_required(t) = 0.1 * load_exp;  % 10%备用
        
        % 计算可用备用
        for s = 1:n_scenarios
            for i = 1:n_units
                reserve_available(t) = reserve_available(t) + joint_prob(s) * ...
                    min(units(i).ramp_up, units(i).P_max*u_opt(i,t)-P_opt(i,t,s));
            end
        end
    end
    
    bar(time, [reserve_available; reserve_required]', 'grouped');
    xlabel('时间 (小时)');
    ylabel('备用容量 (MW)');
    title('旋转备用');
    legend('可用备用', '要求备用', 'Location', 'best');
    grid on;
    
    % 子图8: 场景概率分布
    subplot(3,3,8);
    [sorted_prob, idx] = sort(joint_prob, 'descend');
    bar(1:length(sorted_prob), sorted_prob);
    xlabel('场景编号 (按概率排序)');
    ylabel('概率');
    title('场景概率分布');
    grid on;
    
    % 子图9: 不确定性带
    subplot(3,3,9);
    % 计算负荷的不确定性带
    load_min = min(squeeze(joint_scenarios(:,3,:)), [], 1);
    load_max = max(squeeze(joint_scenarios(:,3,:)), [], 1);
    load_mean = mean(squeeze(joint_scenarios(:,3,:)), 1);
    
    fill([time, fliplr(time)], [load_max, fliplr(load_min)], ...
        [0.8, 0.8, 0.8], 'FaceAlpha', 0.3, 'EdgeColor', 'none');
    hold on;
    plot(time, load_mean, 'b-', 'LineWidth', 2);
    xlabel('时间 (小时)');
    ylabel('负荷 (MW)');
    title('负荷不确定性带');
    legend('不确定性范围', '期望值', 'Location', 'best');
    grid on;
end

四、鲁棒优化模型

4.1 自适应鲁棒优化框架

matlab 复制代码
%% 自适应鲁棒优化:考虑最坏情况下的源荷不确定性
clear; clc;

%% 1. 系统参数
n_hours = 24;
n_units = 3;
n_wind = 1;
n_pv = 1;

%% 2. 不确定性集合定义
% 区间不确定性模型
load_nominal = [120, 115, 110, 105, 100, 110, 130, 150, 170, 180, ...
                175, 170, 165, 160, 155, 160, 170, 185, 190, 180, ...
                170, 160, 140, 125];  % MW

wind_nominal = [45, 48, 50, 52, 55, 60, 65, 70, 75, 80, ...
                78, 75, 72, 70, 68, 65, 62, 60, 58, 55, ...
                52, 50, 48, 46];  % MW

pv_nominal = [0, 0, 0, 0, 0, 5, 15, 30, 45, 60, ...
              70, 75, 80, 75, 70, 60, 45, 30, 15, 5, ...
              0, 0, 0, 0];  % MW

% 不确定性偏差范围 (±百分比)
load_uncertainty = 0.15;  % ±15%
wind_uncertainty = 0.30;  % ±30%
pv_uncertainty = 0.25;    % ±25%

% 预算不确定性集合参数
Gamma_load = 8;  % 负荷不确定性预算
Gamma_wind = 6;  % 风电不确定性预算
Gamma_pv = 4;    % 光伏不确定性预算

%% 3. 鲁棒优化建模
% 使用YALMIP的鲁棒优化功能
yalmip('clear');

% 第一阶段变量: 机组启停
u = binvar(n_units, n_hours, 'full');
v = binvar(n_units, n_hours, 'full');
w = binvar(n_units, n_hours, 'full');

% 第二阶段变量: 机组出力 (作为仿射可调决策)
P = sdpvar(n_units, n_hours, 'full');

% 不确定变量
xi_load = sdpvar(1, n_hours, 'full');  % 负荷不确定性
xi_wind = sdpvar(1, n_hours, 'full');  % 风电不确定性
xi_pv = sdpvar(1, n_hours, 'full');    % 光伏不确定性

% 不确定性集合定义
% 标准化不确定性变量: ξ ∈ [-1, 1]
uncertainty_set = [];
for t = 1:n_hours
    uncertainty_set = [uncertainty_set, -1 <= xi_load(t) <= 1];
    uncertainty_set = [uncertainty_set, -1 <= xi_wind(t) <= 1];
    uncertainty_set = [uncertainty_set, -1 <= xi_pv(t) <= 1];
end

% 预算约束
uncertainty_set = [uncertainty_set, ...
    norm(xi_load, 1) <= Gamma_load, ...
    norm(xi_wind, 1) <= Gamma_wind, ...
    norm(xi_pv, 1) <= Gamma_pv];

% 实际值 = 标称值 + 不确定性
load_actual = load_nominal + load_uncertainty * load_nominal .* xi_load;
wind_actual = wind_nominal + wind_uncertainty * wind_nominal .* xi_wind;
pv_actual = pv_nominal + pv_uncertainty * pv_nominal .* xi_pv;

%% 4. 约束条件
constraints = [];

% 4.1 启停逻辑约束
for i = 1:n_units
    for t = 1:n_hours
        if t > 1
            constraints = [constraints, v(i,t) >= u(i,t) - u(i,t-1)];
            constraints = [constraints, w(i,t) >= u(i,t-1) - u(i,t)];
        else
            constraints = [constraints, v(i,1) >= u(i,1)];
            constraints = [constraints, w(i,1) >= 0 - u(i,1)];
        end
        constraints = [constraints, 0 <= v(i,t) <= 1, 0 <= w(i,t) <= 1];
    end
end

% 4.2 机组出力约束
for i = 1:n_units
    for t = 1:n_hours
        constraints = [constraints, ...
            units(i).P_min * u(i,t) <= P(i,t) <= units(i).P_max * u(i,t)];
    end
end

% 4.3 爬坡约束
for i = 1:n_units
    for t = 2:n_hours
        constraints = [constraints, ...
            P(i,t) - P(i,t-1) <= units(i).ramp_up];
        constraints = [constraints, ...
            P(i,t-1) - P(i,t) <= units(i).ramp_down];
    end
end

% 4.4 功率平衡约束 (鲁棒约束,对所有不确定性实现成立)
power_balance_constraint = [];
for t = 1:n_hours
    total_gen = sum(P(:,t)) + wind_actual(t) + pv_actual(t);
    power_balance_constraint = [power_balance_constraint, ...
        total_gen == load_actual(t)];
end
constraints = [constraints, implies(uncertainty_set, power_balance_constraint)];

% 4.5 备用约束
reserve_constraint = [];
for t = 1:n_hours
    % 计算可用备用
    available_reserve = 0;
    for i = 1:n_units
        available_reserve = available_reserve + ...
            min(units(i).ramp_up, units(i).P_max*u(i,t) - P(i,t));
    end
    
    % 考虑最坏情况下的备用需求
    worst_case_load = load_nominal(t) * (1 + load_uncertainty);
    reserve_requirement = 0.1 * worst_case_load;
    
    reserve_constraint = [reserve_constraint, ...
        available_reserve >= reserve_requirement];
end
constraints = [constraints, reserve_constraint];

%% 5. 目标函数
% 最小化最坏情况下的总成本
total_cost = 0;

% 启停成本
for i = 1:n_units
    for t = 1:n_hours
        total_cost = total_cost + units(i).startup_cost * v(i,t) + ...
                     units(i).shutdown_cost * w(i,t);
    end
end

% 发电成本 (考虑最坏情况)
gen_cost = 0;
for i = 1:n_units
    for t = 1:n_hours
        gen_cost = gen_cost + units(i).a * P(i,t)^2 + ...
                   units(i).b * P(i,t) + units(i).c * u(i,t);
    end
end

% 弃电惩罚 (在最坏情况下)
wind_curtail_penalty = 0;
pv_curtail_penalty = 0;

% 由于是鲁棒优化,需要考虑最坏情况下的弃电
% 简化处理: 假设弃电发生在可再生能源过剩时
for t = 1:n_hours
    % 弃电惩罚项
    wind_curtail_penalty = wind_curtail_penalty + wind_penalty * ...
        max(0, wind_actual(t) - (load_actual(t) - sum(P(:,t)) - pv_actual(t)));
    pv_curtail_penalty = pv_curtail_penalty + pv_penalty * ...
        max(0, pv_actual(t) - (load_actual(t) - sum(P(:,t)) - wind_actual(t)));
end

total_cost = total_cost + gen_cost + wind_curtail_penalty + pv_curtail_penalty;

%% 6. 求解鲁棒优化问题
ops = sdpsettings('solver', 'gurobi', 'robust.lplp', 'duality');
ops.verbose = 1;
ops.gurobi.TimeLimit = 1800;

tic;
diagnostics = optimize([constraints, uncertainty_set], total_cost, ops);
solve_time = toc;

if diagnostics.problem == 0
    disp('=== 鲁棒优化求解成功 ===');
    fprintf('求解时间: %.2f 秒\n', solve_time);
    fprintf('最坏情况总成本: %.2f $\n', value(total_cost));
    
    % 提取结果
    u_robust = value(u);
    P_robust = value(P);
    
    % 分析鲁棒性
    analyze_robustness(u_robust, P_robust, load_nominal, wind_nominal, pv_nominal, ...
        load_uncertainty, wind_uncertainty, pv_uncertainty, units);
    
else
    disp('鲁棒优化求解失败');
    disp(yalmiperror(diagnostics.problem));
end

4.2 鲁棒性分析函数

matlab 复制代码
function analyze_robustness(u_opt, P_opt, load_nominal, wind_nominal, pv_nominal, ...
    load_uncert, wind_uncert, pv_uncert, units)
    
    n_hours = length(load_nominal);
    n_units = size(P_opt, 1);
    time = 1:n_hours;
    
    % 生成最坏情况场景
    n_monte_carlo = 1000;
    feasibility_count = 0;
    cost_distribution = zeros(n_monte_carlo, 1);
    
    for mc = 1:n_monte_carlo
        % 随机生成不确定性实现
        xi_load = 2*rand(1, n_hours) - 1;  % [-1, 1]
        xi_wind = 2*rand(1, n_hours) - 1;
        xi_pv = 2*rand(1, n_hours) - 1;
        
        % 应用预算约束
        if sum(abs(xi_load)) > 8
            xi_load = xi_load * 8 / sum(abs(xi_load));
        end
        if sum(abs(xi_wind)) > 6
            xi_wind = xi_wind * 6 / sum(abs(xi_wind));
        end
        if sum(abs(xi_pv)) > 4
            xi_pv = xi_pv * 4 / sum(abs(xi_pv));
        end
        
        % 计算实际值
        load_actual = load_nominal + load_uncert * load_nominal .* xi_load;
        wind_actual = wind_nominal + wind_uncert * wind_nominal .* xi_wind;
        pv_actual = pv_nominal + pv_uncert * pv_nominal .* xi_pv;
        
        % 检查可行性
        feasible = true;
        
        for t = 1:n_hours
            % 检查功率平衡
            total_gen = sum(P_opt(:,t)) + wind_actual(t) + pv_actual(t);
            if abs(total_gen - load_actual(t)) > 1e-3
                feasible = false;
                break;
            end
            
            % 检查机组约束
            for i = 1:n_units
                if P_opt(i,t) < units(i).P_min * u_opt(i,t) - 1e-3 || ...
                   P_opt(i,t) > units(i).P_max * u_opt(i,t) + 1e-3
                    feasible = false;
                    break;
                end
            end
            
            if ~feasible, break; end
        end
        
        if feasible
            feasibility_count = feasibility_count + 1;
            
            % 计算该场景下的成本
            scenario_cost = 0;
            for i = 1:n_units
                for t = 1:n_hours
                    scenario_cost = scenario_cost + ...
                        units(i).a * P_opt(i,t)^2 + ...
                        units(i).b * P_opt(i,t) + ...
                        units(i).c * u_opt(i,t);
                end
            end
            cost_distribution(mc) = scenario_cost;
        end
    end
    
    feasibility_rate = feasibility_count / n_monte_carlo;
    fprintf('蒙特卡洛可行性检验: %.2f%%\n', feasibility_rate * 100);
    
    % 可视化鲁棒性分析结果
    figure('Position', [100, 100, 1200, 800]);
    
    % 子图1: 成本分布
    subplot(2,3,1);
    histogram(cost_distribution(cost_distribution > 0), 20);
    xlabel('总成本 ($)');
    ylabel('频数');
    title('不同场景下的成本分布');
    grid on;
    
    % 子图2: 最坏情况与标称情况对比
    subplot(2,3,2);
    
    % 计算标称情况下的出力
    P_nominal = zeros(n_units, n_hours);
    for t = 1:n_hours
        % 简单分配: 按机组顺序满足净负荷
        net_load = load_nominal(t) - wind_nominal(t) - pv_nominal(t);
        
        remaining = net_load;
        for i = 1:n_units
            if remaining > 0
                P_nominal(i,t) = min(remaining, units(i).P_max * u_opt(i,t));
                remaining = remaining - P_nominal(i,t);
            end
        end
    end
    
    plot(time, sum(P_opt,1), 'r-', 'LineWidth', 2, 'DisplayName', '鲁棒调度');
    hold on;
    plot(time, sum(P_nominal,1), 'b--', 'LineWidth', 2, 'DisplayName', '标称调度');
    xlabel('时间 (小时)');
    ylabel('常规机组总出力 (MW)');
    title('鲁棒 vs 标称调度');
    legend('Location', 'best');
    grid on;
    
    % 子图3: 备用充足性
    subplot(2,3,3);
    
    reserve_available = zeros(1, n_hours);
    worst_case_reserve_needed = zeros(1, n_hours);
    
    for t = 1:n_hours
        % 可用备用
        for i = 1:n_units
            reserve_available(t) = reserve_available(t) + ...
                min(units(i).ramp_up, units(i).P_max*u_opt(i,t) - P_opt(i,t));
        end
        
        % 最坏情况备用需求
        worst_load = load_nominal(t) * (1 + load_uncert);
        worst_case_reserve_needed(t) = 0.1 * worst_load;
    end
    
    bar(time, [reserve_available; worst_case_reserve_needed]');
    xlabel('时间 (小时)');
    ylabel('备用容量 (MW)');
    title('备用充足性分析');
    legend('可用备用', '最坏情况需求', 'Location', 'best');
    grid on;
    
    % 子图4: 不确定性对功率平衡的影响
    subplot(2,3,4);
    
    % 生成几个极端场景
    n_extreme = 5;
    imbalance_scenarios = zeros(n_extreme, n_hours);
    
    for s = 1:n_extreme
        % 生成极端不确定性
        xi_load_extreme = sign(randn(1, n_hours));
        xi_wind_extreme = sign(randn(1, n_hours));
        xi_pv_extreme = sign(randn(1, n_hours));
        
        % 计算实际值
        load_extreme = load_nominal + load_uncert * load_nominal .* xi_load_extreme;
        wind_extreme = wind_nominal + wind_uncert * wind_nominal .* xi_wind_extreme;
        pv_extreme = pv_nominal + pv_uncert * pv_nominal .* xi_pv_extreme;
        
        % 计算功率不平衡
        for t = 1:n_hours
            total_gen = sum(P_opt(:,t)) + wind_extreme(t) + pv_extreme(t);
            imbalance_scenarios(s,t) = total_gen - load_extreme(t);
        end
    end
    
    plot(time, imbalance_scenarios', 'LineWidth', 1);
    hold on;
    plot(time, zeros(1,n_hours), 'k-', 'LineWidth', 2);
    xlabel('时间 (小时)');
    ylabel('功率不平衡 (MW)');
    title('极端场景下的功率平衡');
    grid on;
    
    % 子图5: 成本保守性分析
    subplot(2,3,5);
    
    % 计算标称成本
    nominal_cost = 0;
    for i = 1:n_units
        for t = 1:n_hours
            nominal_cost = nominal_cost + ...
                units(i).a * P_nominal(i,t)^2 + ...
                units(i).b * P_nominal(i,t) + ...
                units(i).c * u_opt(i,t);
        end
    end
    
    % 鲁棒成本 (期望)
    robust_cost_mean = mean(cost_distribution(cost_distribution > 0));
    robust_cost_max = max(cost_distribution);
    
    bar_data = [nominal_cost, robust_cost_mean, robust_cost_max];
    bar(1:3, bar_data);
    set(gca, 'XTickLabel', {'标称成本', '鲁棒期望成本', '最坏情况成本'});
    ylabel('成本 ($)');
    title('成本保守性分析');
    grid on;
    
    % 添加数值标签
    for i = 1:3
        text(i, bar_data(i), sprintf('%.0f', bar_data(i)), ...
            'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom');
    end
    
    % 子图6: 可行性热图
    subplot(2,3,6);
    
    % 测试不同不确定性水平下的可行性
    gamma_test = 0:2:10;
    feasibility_rates = zeros(length(gamma_test), 1);
    
    for g = 1:length(gamma_test)
        gamma = gamma_test(g);
        
        feasible_count = 0;
        for mc = 1:100
            xi_test = 2*rand(1, n_hours) - 1;
            if sum(abs(xi_test)) > gamma
                xi_test = xi_test * gamma / sum(abs(xi_test));
            end
            
            load_test = load_nominal + load_uncert * load_nominal .* xi_test;
            
            % 简单可行性检查
            feasible = true;
            for t = 1:n_hours
                if load_test(t) > sum(P_opt(:,t)) + wind_nominal(t) + pv_nominal(t) + 10
                    feasible = false;
                    break;
                end
            end
            
            if feasible
                feasible_count = feasible_count + 1;
            end
        end
        
        feasibility_rates(g) = feasible_count / 100;
    end
    
    plot(gamma_test, feasibility_rates*100, 'b-o', 'LineWidth', 2);
    xlabel('不确定性预算 \Gamma');
    ylabel('可行性率 (%)');
    title('不同不确定性水平下的可行性');
    grid on;
    ylim([0, 105]);
end

参考代码 考虑源荷不确定性-电力系统优化 www.youwenfan.com/contentcst/160705.html

五、实际应用建议

5.1 方法选择指南

应用场景 推荐方法 原因
日前市场出清 随机规划 考虑多种可能,经济性较好
实时调度 鲁棒优化 快速响应,保证安全性
规划问题 随机规划+鲁棒优化 兼顾长期经济性和短期可靠性
高可再生能源渗透 随机规划+机会约束 平衡经济性与消纳
极端天气应对 鲁棒优化 抗干扰能力强

5.2 参数设置经验

  1. 场景数:50-200个场景通常足够,更多场景收益递减
  2. 不确定性预算Γ:通常设为不确定性变量数的20-40%
  3. 弃电惩罚:设为最高发电成本的1.2-1.5倍
  4. 备用要求:常规10-15%,高可再生能源时15-20%

5.3 计算效率提升

  1. 并行计算 :使用parfor并行处理场景
  2. 分解算法:Benders分解、场景分解
  3. 场景削减:保留概率大、差异大的场景
  4. 简化模型:线性化、分段线性化复杂函数

六、总结

本文提供了完整的MATLAB实现,涵盖:

  1. 不确定性建模:场景生成与削减
  2. 随机规划:两阶段随机优化模型
  3. 鲁棒优化:自适应鲁棒优化框架
  4. 可视化分析:全面的结果可视化

关键要点:

  • 随机规划更适合追求经济性的场景
  • 鲁棒优化更适合安全要求高的场景
  • 实际应用常结合两种方法
  • 场景质量和数量显著影响结果

后续工作方向

  1. 集成机器学习进行不确定性预测
  2. 考虑网络约束的扩展
  3. 多时间尺度协调优化
  4. 分布式优化算法

代码已模块化设计,便于扩展和应用于实际电力系统。

相关推荐
自信150413057592 小时前
重生之从0开始学习c++之string(上)
开发语言·c++·学习
wangjialelele2 小时前
从零入门 LangChain:Python 语法详解 + 工具开发 + 结构化输出实战
开发语言·人工智能·python·语言模型·langchain
jinanwuhuaguo2 小时前
OpenClaw智能体的涌现与异化——复杂系统演化、知识权力重构与文明纪元跃迁(第五篇)
大数据·开发语言·人工智能·重构·安全架构·openclaw
Dillon Dong2 小时前
【系列主题】拯救 OOM 与构建中断:Next.js 在 Docker 中的静态生成(SSG)避坑指南
开发语言·javascript·docker
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第10题:HashMap中的元素是有序存放的吗
java·开发语言·数据结构·后端·面试·哈希算法·哈希表
itzixiao2 小时前
L1-049 天梯赛座位分配(20 分)[java][python][c]
java·开发语言·python
子非鱼@Itfuture2 小时前
ThreadLocal 是什么?如何用?以及最佳使用场景
java·开发语言·spring
杨凯凡2 小时前
【024】JVM 参数入门:堆、栈、元空间与典型模板
java·开发语言·jvm
不懒不懒2 小时前
【PaddleOCR实战指南:图像文字识别、实时摄像头与PyQt5 GUI开发】
开发语言·python