Solving the Unit Commitment Problem using optimproblem
37 次查看(过去 30 天)
显示 更早的评论
I am trying to solve the Unit Commitment problem using the optimproblem function. I will explain my problem with an example. Lets say I have three generators which will be operated to meet various loads for a 24 hours period. Now the cost curves for these units are quadratic, so piecewise linearization is required if I am going to use the intlinprog function. I have successfully linearized the system and the problem now involves minimizing:
Total C(P) = C_1(P_1min)T_1 + s_11*P_11*T_1 + s_12*P_12*T_1 + … + s_1n*P_1n*T_1
+ C_2(P_2min)T_2 + s_21*P_21*T_2 + s_22*P_22*T_2 + … + s_2n*P_2n*T_2
+ C_3(P_3min)T_3 + s_31*P_31*T_3 + s_32*P_32*T_3 + … + s_3n*P_3n*T_3
Where Sik is the slope for each segment of the linearized curve, Pik are the power increments (which I need to determine) for each segment. T_i is a binary variable which keeps track of the state of unit and Ci(Pimin) is the cost at Pimin. Now based on my research, the problem should now be formulated as minimize:
Total C(P) = C_1(P_1min)T_1 + s_11*Z_11 + s_12*Z_12 + … + s_1n*Z_1n
+ C_2(P_2min)T_2 + s_21*Z_21 + s_22*Z_22 + … + s_2n*Z_2n
+ C_3(P_3min)T_3 + s_31*Z_31 + s_32*Z_32 + … + s_3n*Z_3n
Where Ti = 0 implies that Zik = 0 and Ti = 1 implies that Zik = Pik.
Now I have two optimization variable:
- Pik
- Ti
With the optimization problem being made up of two part:
- Sum of ALL Sik*Pik values
- Sum of Ci(Pimin)*Ti values.
The following code illustrates this (with the addition of another optimization variable which isn't so important):
%Amount of power generated in an hour by a plant
power = optimvar('power',nHours,plant,'LowerBound',0,'UpperBound',maxGenConst);
%Indicator if plant is operating during an hour
isOn = optimvar('isOn',nHours,actual_plant,'Type','integer','LowerBound',0,'UpperBound',1);
%Indicator if plant is starting up during an hour
startup = optimvar('startup',nHours,actual_plant,'Type','integer','LowerBound',0,'UpperBound',1);
%Costs
powerCost = sum(power*f,1);
isOnCost = sum(isOn*OperatingCost',1);
startupCost = sum(startup*StartupCost',1);
% set objective
powerprob.Objective = powerCost + isOnCost + startupCost;
% power generation over all plans meets hourly demand
powerprob.Constraints.isDemandMet = sum(power,2) >= Load;
% only gen power when plant is on
% if isOn=0 power must be zero, if isOn=1 power must be less than maxGenConst
powerprob.Constraints.powerOnlyWhenOn = power <= maxGenConst.*isOn;
% if on, meet MinGenerationLevel
% if isOn=0 power >= 0, if isOn=1 power must be more than minGenConst
powerprob.Constraints.meetMinGenLevel = power >= maxGenConst.*isOn;
My problem lies in this calculation: maxGenConst.*isOn. These have different sizes as maxGenConst is a nHours * (num_of_gen*num_of_segments) whereas isOn is a nHour * num_of_gen. The reason this occurs is because after linearization, the cost equation becomes (num_of_segments + 1) equations. I would appreciate some help in formulating the problem so I can use the optimproblem function. I have attached my full code and data.
4 个评论
Sivateja Maturu
2021-6-16
Can you please explain how you have defined the values of a, b, c for the power plants defined in your Gen_Data?
采纳的回答
更多回答(2 个)
amrit singh
2019-5-19
Undefined function or variable 'optimproblem'.
Error in ELD_LP (line 168)
powerprob = optimproblem;
1 个评论
praveen kumar
2025-10-28,1:34
编辑:Walter Roberson
2025-10-28,1:47
%==========================================================================
% ECONOMIC LOAD DISPATCH - DIAGNOSTIC AND WORKING VERSION
%==========================================================================
clc;
clear;
close all;
%% ==================== DATA INPUT ====================
Load = [140; 166; 180; 196; 220; 240; 267; 283.4; 308; 323; 340; 350; ...
300; 267; 220; 196; 220; 240; 267; 300; 267; 235; 196; 166];
nHours = numel(Load);
% Generator Data: [b, a, c, Pmax, Pmin, MinUpTime, MinDownTime, StartupCost]
gen_data = [2 200 0.00375 200 50 1 1 176;
1.75 257 0.0175 80 20 2 2 187;
1 300 0.0625 40 15 1 1 113;
3.25 400 0.00834 35 10 1 2 267;
3 515 0.025 30 10 2 1 180;
3 515 0.05 25 12 1 1 113];
num_of_gen = size(gen_data, 1);
b_coeff = gen_data(:, 1);
a_coeff = gen_data(:, 2);
c_coeff = gen_data(:, 3);
Pmax = gen_data(:, 4);
Pmin = gen_data(:, 5);
fprintf('========== FEASIBILITY CHECK ==========\n');
fprintf('Peak Load: %.2f MW\n', max(Load));
fprintf('Total Capacity: %.2f MW\n', sum(Pmax));
fprintf('Min Load: %.2f MW\n', min(Load));
fprintf('Total Pmin (all ON): %.2f MW\n\n', sum(Pmin));
% THE ISSUE: Min load (140) is greater than what some generators can provide alone
% but less than total Pmin if all units are ON (117 MW is fine)
% The problem is the PIECEWISE LINEARIZATION creating infeasibility
%% ========== SIMPLIFIED APPROACH WITHOUT PIECEWISE ==========
% Use quadratic costs directly - simpler and more reliable
fprintf('========== USING SIMPLIFIED FORMULATION ==========\n');
% Create optimization problem
prob = optimproblem('ObjectiveSense', 'minimize');
% Decision Variables
% P(t,g) = power output of generator g at hour t
P = optimvar('P', nHours, num_of_gen, 'LowerBound', 0);
% u(t,g) = 1 if generator g is ON at hour t
u = optimvar('u', nHours, num_of_gen, 'Type', 'integer', 'LowerBound', 0, 'UpperBound', 1);
% v(t,g) = 1 if generator g starts up at hour t
v = optimvar('v', nHours, num_of_gen, 'Type', 'integer', 'LowerBound', 0, 'UpperBound', 1);
fprintf('Variables: %d continuous, %d binary\n', nHours*num_of_gen, 2*nHours*num_of_gen);
%% ========== OBJECTIVE FUNCTION ==========
% For optimization, we'll use linear approximation of costs
% Cost ≈ marginal cost * power + fixed cost when on
% Calculate marginal cost at mid-point
marginal_cost = zeros(num_of_gen, 1);
fixed_cost = zeros(num_of_gen, 1);
startup_cost = gen_data(:, 8);
for g = 1:num_of_gen
P_mid = (Pmin(g) + Pmax(g)) / 2;
marginal_cost(g) = 2 * a_coeff(g) * P_mid + b_coeff(g);
fixed_cost(g) = a_coeff(g) * Pmin(g)^2 + b_coeff(g) * Pmin(g) + c_coeff(g);
end
% Objective: minimize total cost
fuel_cost = sum(P * marginal_cost, 'all');
operating_cost = sum(u * fixed_cost, 'all');
startup_cost_total = sum(v * startup_cost, 'all');
prob.Objective = fuel_cost + operating_cost + startup_cost_total;
fprintf('Objective function defined\n');
%% ========== CONSTRAINTS ==========
fprintf('Adding constraints...\n');
% 1. Meet demand
prob.Constraints.demand = sum(P, 2) >= Load;
fprintf(' Demand: %d constraints\n', nHours);
% 2. Minimum generation when ON
for g = 1:num_of_gen
prob.Constraints.(['min_' num2str(g)]) = P(:, g) >= Pmin(g) * u(:, g);
end
fprintf(' Min generation: %d constraints\n', num_of_gen * nHours);
% 3. Maximum generation when ON
for g = 1:num_of_gen
prob.Constraints.(['max_' num2str(g)]) = P(:, g) <= Pmax(g) * u(:, g);
end
fprintf(' Max generation: %d constraints\n', num_of_gen * nHours);
% 4. Startup definition (relaxed)
prob.Constraints.startup = v(2:end, :) >= u(2:end, :) - u(1:end-1, :);
fprintf(' Startup: %d constraints\n', (nHours-1) * num_of_gen);
fprintf('Total constraints: %d\n', nHours + 2*num_of_gen*nHours + (nHours-1)*num_of_gen);
%% ========== SOLVE ==========
fprintf('\n========== SOLVING ==========\n');
options = optimoptions('intlinprog', ...
'MaxTime', 600, ...
'Display', 'iter', ...
'RelativeGapTolerance', 0.1, ...
'MaxNodes', 1e6);
fprintf('Starting solver...\n\n');
tic;
[sol, fval, exitflag, output] = solve(prob, 'Options', options);
solve_time = toc;
%% ========== DISPLAY RESULTS ==========
fprintf('\n========== RESULTS ==========\n');
fprintf('Exit flag: %d\n', exitflag);
fprintf('Solve time: %.2f seconds\n', solve_time);
if exitflag >= 0
fprintf('STATUS: SUCCESS!\n');
fprintf('Total Cost: $%.2f\n', fval);
P_sol = sol.P;
u_sol = sol.u;
v_sol = sol.v;
% Round binary variables
u_sol = round(u_sol);
v_sol = round(v_sol);
fprintf('\n========== GENERATION SCHEDULE ==========\n');
fprintf('Hour\tLoad\tTotal\tUnits\t G1\t G2\t G3\t G4\t G5\t G6\n');
fprintf('----\t----\t-----\t-----\t----\t----\t----\t----\t----\t----\n');
for t = 1:nHours
fprintf('%2d\t%4.0f\t%5.1f\t %d\t', t, Load(t), sum(P_sol(t,:)), sum(u_sol(t,:)));
for g = 1:num_of_gen
if u_sol(t,g) > 0.5
fprintf('%5.1f\t', P_sol(t,g));
else
fprintf(' - \t');
end
end
fprintf('\n');
end
% Calculate actual costs
actual_gen_cost = 0;
actual_op_cost = 0;
for t = 1:nHours
for g = 1:num_of_gen
if u_sol(t,g) > 0.5
P_val = P_sol(t,g);
actual_gen_cost = actual_gen_cost + a_coeff(g)*P_val^2 + b_coeff(g)*P_val + c_coeff(g);
end
end
end
actual_startup_cost = sum(sum(v_sol)) * mean(startup_cost);
fprintf('\n========== COST BREAKDOWN ==========\n');
fprintf('Generation Cost: $%.2f\n', actual_gen_cost);
fprintf('Startup Cost: $%.2f (approx)\n', actual_startup_cost);
fprintf('Total: $%.2f (approx)\n', actual_gen_cost + actual_startup_cost);
fprintf('\n========== STARTUPS ==========\n');
for g = 1:num_of_gen
fprintf('Generator %d: %d startups\n', g, sum(v_sol(:,g)));
end
% Verify demand is met
fprintf('\n========== VERIFICATION ==========\n');
for t = 1:nHours
total_gen = sum(P_sol(t,:));
if total_gen < Load(t) - 0.01
fprintf('WARNING: Hour %d - Generation %.2f < Load %.2f\n', t, total_gen, Load(t));
end
end
fprintf('All demands satisfied!\n');
% Plot results
figure('Position', [100, 100, 1400, 700]);
% Subplot 1: Stacked generation
subplot(2,2,1);
area(1:nHours, P_sol);
hold on;
plot(1:nHours, Load, 'k-', 'LineWidth', 2);
xlabel('Hour');
ylabel('Power (MW)');
title('Generation Dispatch');
legend('G1','G2','G3','G4','G5','G6','Load','Location','eastoutside');
grid on;
% Subplot 2: Unit commitment
subplot(2,2,2);
imagesc(u_sol');
colormap([1 1 1; 0 0.5 0]);
xlabel('Hour');
ylabel('Generator');
title('Unit Commitment Status');
yticks(1:num_of_gen);
yticklabels({'G1','G2','G3','G4','G5','G6'});
colorbar('Ticks',[0.25 0.75],'TickLabels',{'OFF','ON'});
% Subplot 3: Load vs Generation
subplot(2,2,3);
plot(1:nHours, Load, 'b-o', 'LineWidth', 2, 'MarkerFaceColor', 'b');
hold on;
plot(1:nHours, sum(P_sol,2), 'r-s', 'LineWidth', 2, 'MarkerFaceColor', 'r');
xlabel('Hour');
ylabel('Power (MW)');
title('Load vs Total Generation');
legend('Load','Generation','Location','best');
grid on;
% Subplot 4: Generator utilization
subplot(2,2,4);
utilization = zeros(num_of_gen, 1);
for g = 1:num_of_gen
hours_on = sum(u_sol(:,g));
avg_output = sum(P_sol(:,g)) / hours_on;
utilization(g) = avg_output / Pmax(g) * 100;
end
bar(utilization);
xlabel('Generator');
ylabel('Average Utilization (%)');
title('Generator Utilization When ON');
xticklabels({'G1','G2','G3','G4','G5','G6'});
grid on;
sgtitle('Economic Load Dispatch Results', 'FontWeight', 'bold', 'FontSize', 14);
else
fprintf('STATUS: FAILED\n');
fprintf('Message: %s\n', output.message);
% Additional diagnostics
fprintf('\n========== DIAGNOSTICS ==========\n');
fprintf('The problem is infeasible. Possible reasons:\n');
fprintf('1. Check if any hour load > total capacity\n');
for t = 1:nHours
if Load(t) > sum(Pmax)
fprintf(' Hour %d: Load %.0f > Capacity %.0f\n', t, Load(t), sum(Pmax));
end
end
fprintf('2. All capacity checks passed - issue is with constraints\n');
end
fprintf('\nDone.\n');
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Linear Least Squares 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
