220 lines
18 KiB
JSON
220 lines
18 KiB
JSON
{
|
|
"description": "- The energy system includes photovoltaic power stations, wind power stations, generators, batteries, and residential buildings.\n- The goal is to minimize the total costs of the energy system and the gap between power supply and residential load.\n- Electricity price, residential load, photovoltaic, and wind power generation are \\\\param{price_{}}, \\\\param{load_{}}, \\\\param{pv_{}}, and \\\\param{wind_{}}, each with 24 time steps representing hourly data.\n- Battery state of charge is \\\\param{soc_{}}, with a total battery capacity of 500. Power of generators 1, 2, and 3 is \\\\param{pg1_{}}, \\\\param{pg2_{}}, and \\\\param{pg3_{}}, respectively. The initial values at time step 0 are provided, and the system will update these values at each subsequent time step based on decisions made.\n- \\\\var{Apv_{}}, \\\\var{Asoc_{}}, \\\\var{Ag1_{}}, \\\\var{Ag2_{}}, and \\\\var{Ag3_{}} are adjustment factors ranging from -1 to 1, changing according to the value from the previous time step and affecting system parameters such as power generation and battery capacity.\n- Battery charging and discharging result in a capacity change of 100 * \\\\var{Asoc_{t}}.\n- Generators 1, 2, and 3 power change by 100 * \\\\var{Ag1_{t}}, 100 * \\\\var{Ag2_{t}}, and 200 * \\\\var{Ag3_{t}}.\n- \\\\param{soc_{t}} is calculated as (0.18 * \\\\var{Asoc_{t}} + \\\\param{soc_{t-1}}), with a maximum of 0.8 and a minimum of 0.2.\n- \\\\param{pg1_{t}} is calculated as (100 * \\\\var{Ag1_{t}} + \\\\param{pg1_{t-1}}), with a maximum of 150 and a minimum of 10.\n- \\\\param{pg2_{t}} is calculated as (100 * \\\\var{Ag2_{t}} + \\\\param{pg2_{t-1}}), with a maximum of 375 and a minimum of 50.\n- \\\\param{pg3_{t}} is calculated as (200 * \\\\var{Ag3_{t}} + \\\\param{pg3_{t-1}}), with a maximum of 500 and a minimum of 100.\n- Photovoltaic power is calculated as (\\\\param{pv_{t}} * (1 + \\\\var{Apv})).\n- Total power supply at each time step t = \\\\param{soc_{t}} + \\\\param{pg1_{t}} + \\\\param{pg2_{t}} + \\\\param{pg3_{t}}+ (photovoltaic power at time step t) + \\\\param{wind_{t}}.\n- Excess energy = total power supply - \\\\param{load_{t}}, and no less than 0.\n- Shortage energy = \\\\param{load_{t}} - total power supply, and no less than 0.\n- The total cost structure includes the following:\n- Battery cost = \\\\var{Asoc_{t}} + 0.1 * \\\\param{soc_{t}};\n- Gen1 cost = 0.0034 * \\\\param{pg1_{t}}^2 + 3 * \\\\param{pg1_{t}} + 30;\n- Gen2 cost = 0.001 * \\\\param{pg2_{t}}^2 + 10 * \\\\param{pg2_{t}} + 40;\n- Gen3 cost = 0.001 * \\\\param{pg3_{t}}^2 + 15 * \\\\param{pg3_{t}} + 70;\n- Renewable energy cost = 0.01 * (\\\\param{pv_{t}} + \\\\param{wind_{t}});\n- Sales revenue = 0.5 * \\\\param{price_{t}} * (excess energy);\n- Purchase cost = \\\\param{price_{t}} * (shortage energy);\n- Excess penalty = max(0, (excess energy - 100) * 50);\n- Shortage penalty = max(0, (shortage energy - 100) * 50).\n- The cost of each power generation module should be considered when supplying power, usually starting the subsequent generator when the power of the previous generator is insufficient to meet the load.\n- Minimize transactions exceeding the power grid transaction limit to avoid power grid fluctuations affecting the stability of residential electricity consumption.\n- Decisions made at each time step will update \\\\param{soc_{}}, \\\\param{pg1_{}}, \\\\param{pg2_{}}, and \\\\param{pg3_{}}, and these updated values will serve as the starting point for calculations in the next time step.\n",
|
|
"parameters": {
|
|
"TotalBatteryCapacity": {
|
|
"shape": [],
|
|
"definition": "The total capacity of the battery",
|
|
"type": "int"
|
|
},
|
|
"InitialSoc": {
|
|
"shape": [],
|
|
"definition": "Initial state of charge of the battery",
|
|
"type": "float"
|
|
},
|
|
"InitialPg1": {
|
|
"shape": [],
|
|
"definition": "Initial power of generator 1",
|
|
"type": "float"
|
|
},
|
|
"InitialPg2": {
|
|
"shape": [],
|
|
"definition": "Initial power of generator 2",
|
|
"type": "float"
|
|
},
|
|
"InitialPg3": {
|
|
"shape": [],
|
|
"definition": "Initial power of generator 3",
|
|
"type": "float"
|
|
},
|
|
"Price": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"definition": "Electricity price at each time step",
|
|
"type": "float"
|
|
},
|
|
"Load": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"definition": "Residential load at each time step",
|
|
"type": "float"
|
|
},
|
|
"Pv": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"definition": "Photovoltaic power generation at each time step",
|
|
"type": "float"
|
|
},
|
|
"Wind": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"definition": "Wind power generation at each time step",
|
|
"type": "float"
|
|
}
|
|
},
|
|
"objective": {
|
|
"description": "\"The goal is to minimize the total costs of the energy system and the gap between power supply and residential load.\"",
|
|
"formulation": "$\\min \\sum_{t=1}^{24} \\left( \\text{Battery cost}_t + \\text{Gen1 cost}_t + \\text{Gen2 cost}_t + \\text{Gen3 cost}_t + \\text{Renewable energy cost}_t + \\text{Excess penalty}_t + \\text{Shortage penalty}_t - \\text{Sales revenue}_t + \\text{Purchase cost}_t + |\\text{ExcessEnergy}_t| + |\\text{ShortageEnergy}_t| \\right)$",
|
|
"code": "model.setObjective(\n quicksum(\n (Asoc[t] + 0.1 * soc[t-1] +\n 0.0034 * pg1[t-1] ** 2 + 3 * pg1[t-1] + 30 +\n 0.001 * pg2[t-1] ** 2 + 10 * pg2[t-1] + 40 +\n 0.001 * pg3[t-1] ** 2 + 15 * pg3[t-1] + 70 +\n 0.01 * (pv[t-1] + wind[t-1]) +\n max(0, (ExcessEnergy[t] - 100) * 50) +\n max(0, (ShortageEnergy[t] - 100) * 50) -\n 0.5 * Price[t-1] * ExcessEnergy[t] +\n Price[t-1] * ShortageEnergy[t] +\n abs(ExcessEnergy[t]) + abs(ShortageEnergy[t])\n ) for t in range(1, 25)\n ),\n GRB.MINIMIZE\n)"
|
|
},
|
|
"constraints": [
|
|
{
|
|
"description": "Battery state of charge (soc_t) must be between 0.2 and 0.8",
|
|
"formulation": "$0.2 \\leq soc_t \\leq 0.8$",
|
|
"code": "# Preceding state of charge variable initialization\nsoc = InitialSoc\n\n# Loop over each time step to add the soc constraints\nfor t in range(24):\n # Calculate soc_t based on the previous soc and the adjustment factor\n soc_t = 0.18 * Asoc[t] + soc\n \n # Add the lower bound constraint for soc_t\n model.addConstr(soc_t >= 0.2)\n \n # Add the upper bound constraint for soc_t\n model.addConstr(soc_t <= 0.8)\n \n # Update soc to the newly calculated soc_t for the next iteration\n soc = soc_t"
|
|
},
|
|
{
|
|
"description": "Generator 1 power (pg1_t) must be between 10 and 150",
|
|
"formulation": "$10 \\leq pg1_t \\leq 150$",
|
|
"code": "# Assuming decision variables Pg1[t] have been defined for each time step t\nfor t in range(24):\n if t == 0:\n # For the first time step, use the initial value of Pg1\n model.addConstr(Pg1[t] <= 150)\n model.addConstr(Pg1[t] >= 10)\n else:\n # For subsequent time steps, calculate Pg1 based on the previous time step and Ag1\n model.addConstr(Pg1[t] <= 150)\n model.addConstr(Pg1[t] >= 10)\n model.addConstr(Pg1[t] == 100 * Ag1[t] + Pg1[t-1])"
|
|
},
|
|
{
|
|
"description": "Generator 2 power (pg2_t) must be between 50 and 375",
|
|
"formulation": "$50 \\leq pg2_t \\leq 375$",
|
|
"code": "for t in range(1, 24):\n model.addConstr(InitialPg2 + 100 * Ag2[t] >= 50)\n model.addConstr(InitialPg2 + 100 * Ag2[t] <= 375)"
|
|
},
|
|
{
|
|
"description": "Generator 3 power (pg3_t) must be between 100 and 500",
|
|
"formulation": "$100 \\\\leq pg3_t \\\\leq 500$",
|
|
"code": "for t in range(24):\n model.addConstr(Pg3[t] >= 100) # Lower bound constraint for each time step\n model.addConstr(Pg3[t] <= 500) # Upper bound constraint for each time step"
|
|
},
|
|
{
|
|
"description": "Battery state of charge (soc_t) must be calculated as (0.18 * Asoc_t + soc_t-1)",
|
|
"formulation": "$\\\\forall t \\\\in \\\\{1,\\\\dots,24\\\\}, \\\\param{soc_{t}} = 0.18 \\\\cdot \\\\var{Asoc_{t}} + \\\\param{soc_{t-1}}$",
|
|
"code": "# Assuming soc is defined as a list of decision variables for each time step\nsoc = model.addVars(24, lb=0.2, ub=0.8, vtype=GRB.CONTINUOUS, name=\"soc\")\n\n# Loop over each time step starting from 1 up to 24\nfor t in range(1, 24):\n # Add the constraint for the state of charge calculation\n model.addConstr(soc[t] == 0.18 * Asoc[t] + soc[t-1])"
|
|
},
|
|
{
|
|
"description": "Generator 1 power (pg1_t) must be calculated as (100 * Ag1_t + pg1_t-1)",
|
|
"formulation": "$\\\\forall t \\\\in \\\\{1,\\\\dots,24\\\\}, \\\\param{pg1_{t}} = 100 \\\\cdot \\\\var{Ag1_{t}} + \\\\param{pg1_{t-1}}$",
|
|
"code": "for t in range(1, 24):\n model.addConstr(pg1[t] == 100 * Ag1[t] + pg1[t-1])"
|
|
},
|
|
{
|
|
"description": "Generator 2 power (pg2_t) must be calculated as (100 * Ag2_t + pg2_t-1)",
|
|
"formulation": "$\\\\forall t \\\\in \\\\{1,\\\\dots,24\\\\}, \\\\param{pg2_{t}} = 100 \\\\times Ag2_t + \\\\param{pg2_{t-1}}$",
|
|
"code": "# Assuming that `pg2` is a list of Gurobi variables representing the power of Generator 2 at each time step\n# and that `InitialPg2` is a parameter representing the initial power of Generator 2 at time step 0\n\n# Define the Generator 2 power for the first time step, which is the initial value and does not have a constraint\npg2 = [model.addVar(vtype=GRB.CONTINUOUS, lb=50, ub=375, name=\"pg2_0\")]\n\n# Now add the constraints for time steps 1 to 23\nfor t in range(1, 24):\n pg2.append(model.addVar(vtype=GRB.CONTINUOUS, lb=50, ub=375, name=f\"pg2_{t}\"))\n model.addConstr(pg2[t] == 100 * Ag2[t-1] + pg2[t-1])"
|
|
},
|
|
{
|
|
"description": "Generator 3 power (pg3_t) must be calculated as (200 * Ag3_t + pg3_t-1)",
|
|
"formulation": "$\\\\forall t \\\\in \\\\{1,\\\\ldots,24\\\\}, \\\\param{pg3_{t}} = 200 \\\\cdot \\\\var{Ag3_{t}} + \\\\param{pg3_{t-1}}$",
|
|
"code": "# Assuming Pg3 is defined as a list of decision variables representing power of generator 3 at each time step\nfor t in range(1, 24):\n model.addConstr(Pg3[t] == 200 * Ag3[t] + Pg3[t-1])"
|
|
},
|
|
{
|
|
"description": "Photovoltaic power must be calculated as (pv_t * (1 + Apv))",
|
|
"formulation": "$\\\\forall t, PvPower_t = Pv[t] \\\\times (1 + Apv_t)$",
|
|
"code": "for t in range(24):\n model.addConstr(PvPower[t] == Pv[t] * (1 + Apv[t]))"
|
|
},
|
|
{
|
|
"description": "Excess energy must be no less than 0",
|
|
"formulation": "$\\\\forall t, ExcessEnergy[t] \\\\geq 0$",
|
|
"code": "for t in range(24):\n model.addConstr(ExcessEnergy[t] >= 0)"
|
|
},
|
|
{
|
|
"description": "auxiliary constraint",
|
|
"formulation": "$\\\\forall t, ExcessEnergy[t] = TotalSupply[t] - Load[t]$",
|
|
"code": "for t in range(24):\n # Define the total power supply at time step t\n TotalSupply_t = (InitialPg1 + Ag1[t] * 100 +\n InitialPg2 + Ag2[t] * 100 +\n InitialPg3 + Ag3[t] * 200 +\n Pv[t] * (1 + Apv[t]) +\n Wind[t] +\n InitialSoc + Asoc[t] * 0.18)\n # Add the constraint for excess energy at time step t\n model.addConstr(ExcessEnergy[t] == TotalSupply_t - Load[t])"
|
|
},
|
|
{
|
|
"description": "auxiliary constraint",
|
|
"formulation": "$\\\\forall t, TotalSupply[t] = soc[t] + pg1[t] + pg2[t] + pg3[t] + PvPower[t] + Wind[t]$",
|
|
"code": "for t in range(24):\n # Calculate updated generator powers and battery state of charge\n soc_t = InitialSoc + 0.18 * Asoc[t] if t == 0 else soc[t-1] + 0.18 * Asoc[t]\n pg1_t = InitialPg1 + 100 * Ag1[t] if t == 0 else pg1[t-1] + 100 * Ag1[t]\n pg2_t = InitialPg2 + 100 * Ag2[t] if t == 0 else pg2[t-1] + 100 * Ag2[t]\n pg3_t = InitialPg3 + 200 * Ag3[t] if t == 0 else pg3[t-1] + 200 * Ag3[t]\n\n # Calculate photovoltaic power\n PvPower_t = Pv[t] * (1 + Apv[t])\n\n # Add the constraint for total power supply at time t\n model.addConstr(TotalPowerSupply[t] == soc_t + pg1_t + pg2_t + pg3_t + PvPower_t + Wind[t])"
|
|
},
|
|
{
|
|
"description": "Shortage energy must be no less than 0",
|
|
"formulation": "$\\\\forall t, ShortageEnergy[t] \\\\geq 0$",
|
|
"code": "for t in range(24):\n model.addConstr(ShortageEnergy[t] >= 0)"
|
|
},
|
|
{
|
|
"description": "Adjustment factors (Apv, Asoc, Ag1, Ag2, Ag3) must range from -1 to 1",
|
|
"formulation": "$-1 \\leq Apv_t \\leq 1 \\\\quad \\\\forall t \\\\in \\\\{1, \\\\dots, 24\\\\}$\\n$-1 \\leq Asoc_t \\leq 1 \\\\quad \\\\forall t \\\\in \\\\{1, \\\\dots, 24\\\\}$\\n$-1 \\leq Ag1_t \\leq 1 \\\\quad \\\\forall t \\\\in \\\\{1, \\\\dots, 24\\\\}$\\n$-1 \\leq Ag2_t \\leq 1 \\\\quad \\\\forall t \\\\in \\\\{1, \\\\dots, 24\\\\}$\\n$-1 \\leq Ag3_t \\leq 1 \\\\quad \\\\forall t \\\\in \\\\{1, \\\\dots, 24\\\\}$",
|
|
"code": "for t in range(24):\n model.addConstr(-1 <= Apv[t])\n model.addConstr(Apv[t] <= 1)\n model.addConstr(-1 <= Asoc[t])\n model.addConstr(Asoc[t] <= 1)\n model.addConstr(-1 <= Ag1[t])\n model.addConstr(Ag1[t] <= 1)\n model.addConstr(-1 <= Ag2[t])\n model.addConstr(Ag2[t] <= 1)\n model.addConstr(-1 <= Ag3[t])\n model.addConstr(Ag3[t] <= 1)"
|
|
},
|
|
{
|
|
"description": "Battery charging and discharging must result in a capacity change of 100 * Asoc_t",
|
|
"formulation": "$\\\\forall t, 100 \\\\times Asoc_t = soc_{t} - soc_{t-1}$",
|
|
"code": "for t in range(1, 24):\n model.addConstr(100 * Asoc[t] == soc[t] - soc[t-1])"
|
|
},
|
|
{
|
|
"description": "The sum of power from generators and renewable sources must not exceed the residential load by more than the grid transaction limit to avoid instability",
|
|
"formulation": "$\\\\forall t, TotalPowerSupply[t] \\\\leq Load[t] + GridTransactionLimit$",
|
|
"code": "for t in range(24):\n # Calculate the power from each generator based on previous state and adjustment\n pg1_power = InitialPg1 + 100 * Ag1[t]\n pg2_power = InitialPg2 + 100 * Ag2[t]\n pg3_power = InitialPg3 + 200 * Ag3[t]\n\n # Calculate the adjusted photovoltaic power\n pv_power = Pv[t] * (1 + Apv[t])\n\n # Express the total power supply\n TotalPowerSupply[t] = pg1_power + pg2_power + pg3_power + pv_power + Wind[t]\n\n # Add the constraint that total power supply cannot exceed the load by more than the grid transaction limit\n model.addConstr(TotalPowerSupply[t] <= Load[t] + GridTransactionLimit)"
|
|
},
|
|
{
|
|
"description": "auxiliary constraint",
|
|
"formulation": "$\\\\forall t, TotalPowerSupply[t] = Pg1[t] + Pg2[t] + Pg3[t] + PvPower[t] + Wind[t]$",
|
|
"code": "for t in range(24):\n # Assuming that Pg1, Pg2, Pg3 are defined as variables in the model with the correct initial values and adjustments\n Pg1[t] = model.addVar(vtype=GRB.CONTINUOUS, name=f\"Pg1_{t}\")\n Pg2[t] = model.addVar(vtype=GRB.CONTINUOUS, name=f\"Pg2_{t}\")\n Pg3[t] = model.addVar(vtype=GRB.CONTINUOUS, name=f\"Pg3_{t}\")\n\n # Define the auxiliary constraint for each time step\n model.addConstr(TotalPowerSupply[t] == Pg1[t] + Pg2[t] + Pg3[t] + PvPower[t] + Wind[t])"
|
|
}
|
|
],
|
|
"variables": {
|
|
"Ag1": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "Adjustment factor for generator 1 power at each time step"
|
|
},
|
|
"Ag2": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "Adjustment factor for generator 2 power at each time step"
|
|
},
|
|
"Ag3": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "Adjustment factor for generator 3 power at each time step"
|
|
},
|
|
"PvPower": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "The adjusted photovoltaic power generation at each time step"
|
|
},
|
|
"Apv": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "The adjustment factor for photovoltaic power at each time step"
|
|
},
|
|
"ExcessEnergy": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "The excess energy at each time step"
|
|
},
|
|
"ShortageEnergy": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "The shortage energy at each time step"
|
|
},
|
|
"Asoc": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "The adjustment factor for the battery state of charge at each time step"
|
|
},
|
|
"TotalPowerSupply": {
|
|
"shape": [
|
|
24
|
|
],
|
|
"type": "continuous",
|
|
"definition": "The total power supply from generators and renewable sources at each time step"
|
|
},
|
|
"GridTransactionLimit": {
|
|
"shape": [],
|
|
"type": "float",
|
|
"definition": "The maximum allowable excess power supply over the residential load to maintain grid stability"
|
|
}
|
|
}
|
|
} |