├── EconomicDispatch
├── Instructions for code.txt
├── Integer
│ ├── CaseStudy_2gen.m
│ ├── FR_limits.jpg
│ └── setNadir.m
└── Relaxed
│ ├── CaseStudy_2gen.m
│ ├── NOTE about NaN duals.txt
│ ├── setNadir.m
│ └── study_duals.m
├── README.md
├── UnitCommitment
├── Instructions for code.txt
├── Integer
│ ├── CaseStudy_2gen.m
│ └── setNadir.m
└── Relaxed
│ ├── CaseStudy_2gen.m
│ ├── pricing
│ ├── CaseStudy_2gen.m
│ ├── NOTE about NaN duals.txt
│ ├── setNadir.m
│ └── study_duals.m
│ └── setNadir.m
└── simple_EconomicDispatch_YALMIP.m
/EconomicDispatch/Instructions for code.txt:
--------------------------------------------------------------------------------
1 | 1. First solve the file in folder "Integer"
2 |
3 | 2. Then copy file "CaseStudy_2gen.m" to folder "Relaxed", and make sure that the right interval for nadir is fixed in "setNadir.m" (you can know the interval when nadir was chosen to happen from the solution of the Integer optimisation)
4 |
5 | 3. Make sure that you know which services were delivered after and before nadir when calculating the prices in file "study_duals.m"
--------------------------------------------------------------------------------
/EconomicDispatch/Integer/CaseStudy_2gen.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/EconomicDispatch/Integer/CaseStudy_2gen.m
--------------------------------------------------------------------------------
/EconomicDispatch/Integer/FR_limits.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/EconomicDispatch/Integer/FR_limits.jpg
--------------------------------------------------------------------------------
/EconomicDispatch/Integer/setNadir.m:
--------------------------------------------------------------------------------
1 | function [DV_Total_FR_atTd,Inertia_term,PLoss_term,FR_term,Bounds,...
2 | Nadir_constraints] = ...
3 | setNadir(InputData,FR,H_total,DV_PLoss,Bounds)
4 |
5 | % Author: Luis Badesa
6 |
7 | Td = InputData.Td;
8 | Pmax = InputData.Pmax;
9 | PLossMax = InputData.PLossMax;
10 | nadir_req = InputData.nadir_req;
11 | FR_capacity = InputData.FR_capacity;
12 | H_const = InputData.H_const;
13 | H_const_Wind = InputData.H_const_Wind;
14 | H_const_Nuclear = InputData.H_const_Nuclear;
15 | Wind = InputData.Wind;
16 |
17 | %% First define the conditions for nadir happenning in different intervals:
18 | for i=1:length(Td)
19 | for j=1:length(Td)
20 | if Td(j)>Td(i)
21 | if j==1
22 | DV_Total_FR_atTd(i) = sdpvar(1);
23 | DV_Total_FR_atTd(i) = FR(j)*Td(i)/Td(j);
24 | else
25 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
26 | + FR(j)*Td(i)/Td(j);
27 | end
28 | else
29 | if j==1
30 | DV_Total_FR_atTd(i) = sdpvar(1);
31 | DV_Total_FR_atTd(i) = FR(j);
32 | else
33 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
34 | + FR(j);
35 | end
36 | end
37 | end
38 | end
39 | clear i j
40 | Bounds = [Bounds,...
41 | 0 <= DV_Total_FR_atTd <= sum(FR_capacity)*ones(1,length(Td))];
42 | % Not the tightest bounds possible, but these bounds are good enough
43 |
44 |
45 |
46 | %% Define the left-hand and right-hand sides of each nadir constraint:
47 |
48 | Inertia_term = sdpvar(1,length(Td));
49 | PLoss_term = sdpvar(1,length(Td));
50 | FR_term = sdpvar(1,length(Td));
51 |
52 | for i=1:length(Td)
53 | Inertia_term(i) = H_total;
54 | PLoss_term(i) = DV_PLoss;
55 |
56 | FR_term_defined = false;
57 |
58 | for j=1:length(Td)
59 | if Td(j)
=DV_PLoss-tol,...
104 | [norm([Inertia_term(i)-FR_term(i);...
105 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
106 | -Inertia_term(i);...
107 | -FR_term(i)]...
108 | <= [Inertia_term(i)+FR_term(i);...
109 | 0;...
110 | 0]) ];
111 | % This is to enforce nonnegativity of Inertia_term and
112 | % FR_term, but only for the SOC constraint that is actually
113 | % enforced by the conditional statements. Remember that
114 | % nonnegativity is a necessary condition for the rotated SOC to
115 | % be convex.
116 | else
117 | Nadir_constraints = [Nadir_constraints,...
118 | implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
119 | DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
120 | [norm([Inertia_term(i)-FR_term(i);...
121 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
122 | -Inertia_term(i);...
123 | -FR_term(i)]...
124 | <= [Inertia_term(i)+FR_term(i);...
125 | 0;...
126 | 0]) ];
127 | end
128 | end
129 |
130 |
131 | end
132 |
--------------------------------------------------------------------------------
/EconomicDispatch/Relaxed/CaseStudy_2gen.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/EconomicDispatch/Relaxed/CaseStudy_2gen.m
--------------------------------------------------------------------------------
/EconomicDispatch/Relaxed/NOTE about NaN duals.txt:
--------------------------------------------------------------------------------
1 | If after solving the optimisation the duals take value "NaN", change the value of "tol" in "setNadir.m" until the duals work
--------------------------------------------------------------------------------
/EconomicDispatch/Relaxed/setNadir.m:
--------------------------------------------------------------------------------
1 | function [DV_Total_FR_atTd,Inertia_term,PLoss_term,FR_term,Bounds,...
2 | Nadir_constraints] = ...
3 | setNadir(InputData,FR,H_total,DV_PLoss,Bounds)
4 |
5 | % Author: Luis Badesa
6 |
7 | Td = InputData.Td;
8 | Pmax = InputData.Pmax;
9 | PLossMax = InputData.PLossMax;
10 | nadir_req = InputData.nadir_req;
11 | FR_capacity = InputData.FR_capacity;
12 | H_const = InputData.H_const;
13 | H_const_Wind = InputData.H_const_Wind;
14 | H_const_Nuclear = InputData.H_const_Nuclear;
15 | Wind = InputData.Wind;
16 |
17 | %% First define the conditions for nadir happenning in different intervals:
18 | for i=1:length(Td)
19 | for j=1:length(Td)
20 | if Td(j)>Td(i)
21 | if j==1
22 | DV_Total_FR_atTd(i) = sdpvar(1);
23 | DV_Total_FR_atTd(i) = FR(j)*Td(i)/Td(j);
24 | else
25 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
26 | + FR(j)*Td(i)/Td(j);
27 | end
28 | else
29 | if j==1
30 | DV_Total_FR_atTd(i) = sdpvar(1);
31 | DV_Total_FR_atTd(i) = FR(j);
32 | else
33 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
34 | + FR(j);
35 | end
36 | end
37 | end
38 | end
39 | clear i j
40 | Bounds = [Bounds,...
41 | 0 <= DV_Total_FR_atTd <= sum(FR_capacity)*ones(1,length(Td))];
42 | % Not the tightest bounds possible, but these bounds are good enough
43 |
44 |
45 |
46 | %% Define the left-hand and right-hand sides of each nadir constraint:
47 |
48 | Inertia_term = sdpvar(1,length(Td));
49 | PLoss_term = sdpvar(1,length(Td));
50 | FR_term = sdpvar(1,length(Td));
51 |
52 | for i=1:length(Td)
53 | Inertia_term(i) = H_total;
54 | PLoss_term(i) = DV_PLoss;
55 |
56 | FR_term_defined = false;
57 |
58 | for j=1:length(Td)
59 | if Td(j) | =DV_PLoss-tol,...
109 | % [norm([Inertia_term(i)-FR_term(i);...
110 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
111 | % -Inertia_term(i);...
112 | % -FR_term(i)]...
113 | % <= [Inertia_term(i)+FR_term(i);...
114 | % 0;...
115 | % 0]) ];
116 | % % This is to enforce nonnegativity of Inertia_term and
117 | % % FR_term, but only for the SOC constraint that is actually
118 | % % enforced by the conditional statements. Remember that
119 | % % nonnegativity is a necessary condition for the rotated SOC to
120 | % % be convex.
121 | % else
122 | % Nadir_constraints = [Nadir_constraints,...
123 | % implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
124 | % DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
125 | % [norm([Inertia_term(i)-FR_term(i);...
126 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
127 | % -Inertia_term(i);...
128 | % -FR_term(i)]...
129 | % <= [Inertia_term(i)+FR_term(i);...
130 | % 0;...
131 | % 0]) ];
132 |
133 |
134 | % If nadir happens in time-interval i=1, enforce this
135 | % constraint:
136 | Nadir_constraints = [Nadir_constraints,...
137 | (DV_Total_FR_atTd(i)>=DV_PLoss-tol):'limits',...
138 | (cone([Inertia_term(i)-FR_term(i);...
139 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)],...
140 | Inertia_term(i)+FR_term(i))):'nadir',...
141 | Inertia_term(i)>=0,...
142 | FR_term(i)>=0];
143 | % % Otherwise, enforce this constraint:
144 | % Nadir_constraints = [Nadir_constraints,...
145 | % (DV_Total_FR_atTd(i-1)<=DV_PLoss+tol):'limits',...
146 | % (DV_Total_FR_atTd(i)>=DV_PLoss-tol):'limits',...
147 | % (cone([Inertia_term(i)-FR_term(i);...
148 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)],...
149 | % Inertia_term(i)+FR_term(i))):'nadir',...
150 | % Inertia_term(i)>=0,...
151 | % FR_term(i)>=0];
152 |
153 |
154 | % It is better to use "cone" that using "norm", see why here: https://yalmip.github.io/command/cone/
155 | % Also, as I want to obtain the vector duals of the SOCP, I
156 | % need to use "cone", as explained here: https://groups.google.com/forum/#!topic/yalmip/HEjNiiUm-5Q
157 |
158 |
159 | %end
160 | end
161 |
162 |
163 | end
164 |
--------------------------------------------------------------------------------
/EconomicDispatch/Relaxed/study_duals.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/EconomicDispatch/Relaxed/study_duals.m
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MultiFR_optimisation
2 | Joint market clearing of energy and frequency services, including a pricing methodology.
3 |
4 | Frequency services include:
5 | - **Inertia**.
6 | - Different types of **Frequency Response (FR)**, allowing to consider any combination of FR dynamics.
7 | - An **optimised largest-loss** (the code considers the N-1 reliability requirement for scheduling frequency services).
8 |
9 | The code is self-explanatory. For further explanation, refer to [this paper](
10 | http://arxiv.org/abs/1909.06671).
11 |
12 | The optimisation problem is solved via the toolbox **YALMIP**, you can find instructions for how to install it [here](https://yalmip.github.io/tutorial/installation/). You will also need to install some external MISOCP solver like Mosek or Gurobi, both of which have academic licenses available. Remember to also install the Matlab functionalities of that solver.
13 |
14 | YALMIP is very easy to use. Once installed, you can learn how to use it with file "simple_EconomicDispatch_YALMIP.m", contained in this repository, and through the documentation available in YALMIP's website.
15 |
16 | This code has been tested with MATLAB version 2017b.
17 |
18 | ----
19 |
20 | If you use this code for your own work, please cite this paper:
21 |
22 | - L. Badesa, F. Teng, and G. Strbac, "Pricing inertia and frequency response with diverse dynamics in a Mixed-Integer Second-Order Cone Programming formulation," Applied Energy, vol. 260, article 114334, 2020.
23 |
24 |
--------------------------------------------------------------------------------
/UnitCommitment/Instructions for code.txt:
--------------------------------------------------------------------------------
1 | 1. First solve the file in folder "Integer"
2 |
3 | 2. Then copy file "CaseStudy_2gen.m" to folder "Relaxed", and relax the integer commitment Decision Variable to continuous, by changing "y = binvar(num_Clusters,1);" to "y = sdpvar(num_Clusters,1);"
4 |
5 | 3. Then copy that relaxed "CaseStudy_2gen.m" file into the "pricing" folder, where the binary variables related to the conditional nadir constraints are removed because the time-interval for nadir to happen is fixed. Make sure that that the right interval for nadir is fixed in "setNadir.m" (you can know the interval when nadir was chosen to happen from the solution of the Relaxed optimisation)
6 |
7 | 4. Make sure that you know which services were delivered after and before nadir when calculating the prices in file "study_duals.m"
--------------------------------------------------------------------------------
/UnitCommitment/Integer/CaseStudy_2gen.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/UnitCommitment/Integer/CaseStudy_2gen.m
--------------------------------------------------------------------------------
/UnitCommitment/Integer/setNadir.m:
--------------------------------------------------------------------------------
1 | function [DV_Total_FR_atTd,Inertia_term,PLoss_term,FR_term,Bounds,...
2 | Nadir_constraints] = ...
3 | setNadir(InputData,FR,H_total,DV_PLoss,Bounds)
4 |
5 | % Author: Luis Badesa
6 |
7 | Td = InputData.Td;
8 | Pmax = InputData.Gen_limits(:,2);
9 | PLossMax = InputData.PLossMax;
10 | nadir_req = InputData.nadir_req;
11 | FR_capacity = InputData.FR_capacity;
12 | H_const = InputData.H_const;
13 | H_const_Wind = InputData.H_const_Wind;
14 | H_const_Nuclear = InputData.H_const_Nuclear;
15 | P_Wind = InputData.P_Wind;
16 | num_gen = InputData.num_gen;
17 |
18 | %% First define the conditions for nadir happenning in different intervals:
19 | for i=1:length(Td)
20 | for j=1:length(Td)
21 | if Td(j)>Td(i)
22 | if j==1
23 | DV_Total_FR_atTd(i) = sdpvar(1);
24 | DV_Total_FR_atTd(i) = FR(j)*Td(i)/Td(j);
25 | else
26 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
27 | + FR(j)*Td(i)/Td(j);
28 | end
29 | else
30 | if j==1
31 | DV_Total_FR_atTd(i) = sdpvar(1);
32 | DV_Total_FR_atTd(i) = FR(j);
33 | else
34 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
35 | + FR(j);
36 | end
37 | end
38 | end
39 | end
40 | clear i j
41 | Bounds = [Bounds,...
42 | 0 <= DV_Total_FR_atTd <= (num_gen'*FR_capacity)*ones(1,length(Td))];
43 | % Not the tightest bounds possible, but these bounds are good enough
44 |
45 |
46 |
47 | %% Define the left-hand and right-hand sides of each nadir constraint:
48 |
49 | Inertia_term = sdpvar(1,length(Td));
50 | PLoss_term = sdpvar(1,length(Td));
51 | FR_term = sdpvar(1,length(Td));
52 |
53 | for i=1:length(Td)
54 | Inertia_term(i) = H_total;
55 | PLoss_term(i) = DV_PLoss;
56 |
57 | FR_term_defined = false;
58 |
59 | for j=1:length(Td)
60 | if Td(j) | =DV_PLoss-tol,...
109 | % norm([Inertia_term(i)-FR_term(i);...
110 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)])...
111 | % <= Inertia_term(i)+FR_term(i))];
112 | Nadir_constraints = [Nadir_constraints,...
113 | implies(DV_Total_FR_atTd(i)>=DV_PLoss-tol,...
114 | [norm([Inertia_term(i)-FR_term(i);...
115 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
116 | -Inertia_term(i);...
117 | -FR_term(i)]...
118 | <= [Inertia_term(i)+FR_term(i);...
119 | 0;...
120 | 0]) ];
121 | % This is to enforce nonnegativity of Inertia_term and
122 | % FR_term, but only for the SOC constraint that is actually
123 | % enforced by the conditional statements. Remember that
124 | % nonnegativity is a necessary condition for the rotated SOC to
125 | % be convex.
126 | else
127 | % Nadir_constraints = [Nadir_constraints,...
128 | % implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
129 | % DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
130 | % norm([Inertia_term(i)-FR_term(i);...
131 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)])...
132 | % <= Inertia_term(i)+FR_term(i))];
133 | Nadir_constraints = [Nadir_constraints,...
134 | implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
135 | DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
136 | [norm([Inertia_term(i)-FR_term(i);...
137 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
138 | -Inertia_term(i);...
139 | -FR_term(i)]...
140 | <= [Inertia_term(i)+FR_term(i);...
141 | 0;...
142 | 0]) ];
143 | end
144 | end
145 |
146 |
147 | end
148 |
--------------------------------------------------------------------------------
/UnitCommitment/Relaxed/CaseStudy_2gen.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/UnitCommitment/Relaxed/CaseStudy_2gen.m
--------------------------------------------------------------------------------
/UnitCommitment/Relaxed/pricing/CaseStudy_2gen.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/UnitCommitment/Relaxed/pricing/CaseStudy_2gen.m
--------------------------------------------------------------------------------
/UnitCommitment/Relaxed/pricing/NOTE about NaN duals.txt:
--------------------------------------------------------------------------------
1 | If after solving the optimisation the duals take value "NaN", change the value of "tol" in "setNadir.m" until the duals work
--------------------------------------------------------------------------------
/UnitCommitment/Relaxed/pricing/setNadir.m:
--------------------------------------------------------------------------------
1 | function [DV_Total_FR_atTd,Inertia_term,PLoss_term,FR_term,Bounds,...
2 | Nadir_constraints] = ...
3 | setNadir(InputData,FR,H_total,DV_PLoss,Bounds)
4 |
5 | % Author: Luis Badesa
6 |
7 | Td = InputData.Td;
8 | Pmax = InputData.Gen_limits(:,2);
9 | PLossMax = InputData.PLossMax;
10 | nadir_req = InputData.nadir_req;
11 | FR_capacity = InputData.FR_capacity;
12 | H_const = InputData.H_const;
13 | H_const_Wind = InputData.H_const_Wind;
14 | H_const_Nuclear = InputData.H_const_Nuclear;
15 | P_Wind = InputData.P_Wind;
16 | num_gen = InputData.num_gen;
17 |
18 | %% First define the conditions for nadir happenning in different intervals:
19 | for i=1:length(Td)
20 | for j=1:length(Td)
21 | if Td(j)>Td(i)
22 | if j==1
23 | DV_Total_FR_atTd(i) = sdpvar(1);
24 | DV_Total_FR_atTd(i) = FR(j)*Td(i)/Td(j);
25 | else
26 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
27 | + FR(j)*Td(i)/Td(j);
28 | end
29 | else
30 | if j==1
31 | DV_Total_FR_atTd(i) = sdpvar(1);
32 | DV_Total_FR_atTd(i) = FR(j);
33 | else
34 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
35 | + FR(j);
36 | end
37 | end
38 | end
39 | end
40 | clear i j
41 | Bounds = [Bounds,...
42 | 0 <= DV_Total_FR_atTd <= (num_gen'*FR_capacity)*ones(1,length(Td))];
43 | % Not the tightest bounds possible, but these bounds are good enough
44 |
45 |
46 |
47 | %% Define the left-hand and right-hand sides of each nadir constraint:
48 |
49 | Inertia_term = sdpvar(1,length(Td));
50 | PLoss_term = sdpvar(1,length(Td));
51 | FR_term = sdpvar(1,length(Td));
52 |
53 | for i=1:length(Td)
54 | Inertia_term(i) = H_total;
55 | PLoss_term(i) = DV_PLoss;
56 |
57 | FR_term_defined = false;
58 |
59 | for j=1:length(Td)
60 | if Td(j) | =DV_PLoss-tol,...
110 | % [norm([Inertia_term(i)-FR_term(i);...
111 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
112 | % -Inertia_term(i);...
113 | % -FR_term(i)]...
114 | % <= [Inertia_term(i)+FR_term(i);...
115 | % 0;...
116 | % 0]) ];
117 | % % This is to enforce nonnegativity of Inertia_term and
118 | % % FR_term, but only for the SOC constraint that is actually
119 | % % enforced by the conditional statements. Remember that
120 | % % nonnegativity is a necessary condition for the rotated SOC to
121 | % % be convex.
122 | % else
123 | % Nadir_constraints = [Nadir_constraints,...
124 | % implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
125 | % DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
126 | % [norm([Inertia_term(i)-FR_term(i);...
127 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
128 | % -Inertia_term(i);...
129 | % -FR_term(i)]...
130 | % <= [Inertia_term(i)+FR_term(i);...
131 | % 0;...
132 | % 0]) ];
133 |
134 |
135 | % If nadir happens in time-interval i=1, enforce this
136 | % constraint:
137 | Nadir_constraints = [Nadir_constraints,...
138 | (DV_Total_FR_atTd(i)>=DV_PLoss-tol):'limits',...
139 | (cone([Inertia_term(i)-FR_term(i);...
140 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)],...
141 | Inertia_term(i)+FR_term(i))):'nadir',...
142 | Inertia_term(i)>=0,...
143 | FR_term(i)>=0];
144 | % % Otherwise, enforce this constraint:
145 | % Nadir_constraints = [Nadir_constraints,...
146 | % (DV_Total_FR_atTd(i-1)<=DV_PLoss+tol):'limits',...
147 | % (DV_Total_FR_atTd(i)>=DV_PLoss-tol):'limits',...
148 | % (cone([Inertia_term(i)-FR_term(i);...
149 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)],...
150 | % Inertia_term(i)+FR_term(i))):'nadir',...
151 | % Inertia_term(i)>=0,...
152 | % FR_term(i)>=0];
153 |
154 |
155 | % It is better to use "cone" that using "norm", see why here: https://yalmip.github.io/command/cone/
156 | % Also, as I want to obtain the vector duals of the SOCP, I
157 | % need to use "cone", as explained here: https://groups.google.com/forum/#!topic/yalmip/HEjNiiUm-5Q
158 |
159 |
160 | %end
161 | end
162 |
163 |
164 | end
165 |
--------------------------------------------------------------------------------
/UnitCommitment/Relaxed/pricing/study_duals.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/UnitCommitment/Relaxed/pricing/study_duals.m
--------------------------------------------------------------------------------
/UnitCommitment/Relaxed/setNadir.m:
--------------------------------------------------------------------------------
1 | function [DV_Total_FR_atTd,Inertia_term,PLoss_term,FR_term,Bounds,...
2 | Nadir_constraints] = ...
3 | setNadir(InputData,FR,H_total,DV_PLoss,Bounds)
4 |
5 | % Author: Luis Badesa
6 |
7 | Td = InputData.Td;
8 | Pmax = InputData.Gen_limits(:,2);
9 | PLossMax = InputData.PLossMax;
10 | nadir_req = InputData.nadir_req;
11 | FR_capacity = InputData.FR_capacity;
12 | H_const = InputData.H_const;
13 | H_const_Wind = InputData.H_const_Wind;
14 | H_const_Nuclear = InputData.H_const_Nuclear;
15 | P_Wind = InputData.P_Wind;
16 | num_gen = InputData.num_gen;
17 |
18 | %% First define the conditions for nadir happenning in different intervals:
19 | for i=1:length(Td)
20 | for j=1:length(Td)
21 | if Td(j)>Td(i)
22 | if j==1
23 | DV_Total_FR_atTd(i) = sdpvar(1);
24 | DV_Total_FR_atTd(i) = FR(j)*Td(i)/Td(j);
25 | else
26 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
27 | + FR(j)*Td(i)/Td(j);
28 | end
29 | else
30 | if j==1
31 | DV_Total_FR_atTd(i) = sdpvar(1);
32 | DV_Total_FR_atTd(i) = FR(j);
33 | else
34 | DV_Total_FR_atTd(i) = DV_Total_FR_atTd(i)...
35 | + FR(j);
36 | end
37 | end
38 | end
39 | end
40 | clear i j
41 | Bounds = [Bounds,...
42 | 0 <= DV_Total_FR_atTd <= (num_gen'*FR_capacity)*ones(1,length(Td))];
43 | % Not the tightest bounds possible, but these bounds are good enough
44 |
45 |
46 |
47 | %% Define the left-hand and right-hand sides of each nadir constraint:
48 |
49 | Inertia_term = sdpvar(1,length(Td));
50 | PLoss_term = sdpvar(1,length(Td));
51 | FR_term = sdpvar(1,length(Td));
52 |
53 | for i=1:length(Td)
54 | Inertia_term(i) = H_total;
55 | PLoss_term(i) = DV_PLoss;
56 |
57 | FR_term_defined = false;
58 |
59 | for j=1:length(Td)
60 | if Td(j) | =DV_PLoss-tol,...
109 | % norm([Inertia_term(i)-FR_term(i);...
110 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)])...
111 | % <= Inertia_term(i)+FR_term(i))];
112 | Nadir_constraints = [Nadir_constraints,...
113 | implies(DV_Total_FR_atTd(i)>=DV_PLoss-tol,...
114 | [norm([Inertia_term(i)-FR_term(i);...
115 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
116 | -Inertia_term(i);...
117 | -FR_term(i)]...
118 | <= [Inertia_term(i)+FR_term(i);...
119 | 0;...
120 | 0]) ];
121 | % This is to enforce nonnegativity of Inertia_term and
122 | % FR_term, but only for the SOC constraint that is actually
123 | % enforced by the conditional statements. Remember that
124 | % nonnegativity is a necessary condition for the rotated SOC to
125 | % be convex.
126 | else
127 | % Nadir_constraints = [Nadir_constraints,...
128 | % implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
129 | % DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
130 | % norm([Inertia_term(i)-FR_term(i);...
131 | % 2*sqrt(1/(4*nadir_req))*PLoss_term(i)])...
132 | % <= Inertia_term(i)+FR_term(i))];
133 | Nadir_constraints = [Nadir_constraints,...
134 | implies([DV_Total_FR_atTd(i-1)<=DV_PLoss+tol,...
135 | DV_Total_FR_atTd(i)>=DV_PLoss-tol],...
136 | [norm([Inertia_term(i)-FR_term(i);...
137 | 2*sqrt(1/(4*nadir_req))*PLoss_term(i)]);...
138 | -Inertia_term(i);...
139 | -FR_term(i)]...
140 | <= [Inertia_term(i)+FR_term(i);...
141 | 0;...
142 | 0]) ];
143 | end
144 | end
145 |
146 |
147 | end
148 |
--------------------------------------------------------------------------------
/simple_EconomicDispatch_YALMIP.m:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/badber/MultiFR_optimisation/e5034bb2a7a92eede407e380403c3423eab4c7a5/simple_EconomicDispatch_YALMIP.m
--------------------------------------------------------------------------------
|