Оптимизатор переключает накопитель энергии в зависимости от емкости и net нагрузки - PullRequest
3 голосов
/ 24 апреля 2020

Я пытаюсь, чтобы оптимизатор использовал два накопителя энергии для цикла c выработки и потребления энергии. Цель состоит в том, чтобы он отключил первичное накопление энергии (в данном случае аккумулятор c), когда он достигнет полной емкости, а затем сначала разрядился, пока не разрядится. Вторичное хранилище должно заряжаться после основного и разряжаться после основного хранения. Я хотел бы, чтобы оптимизатор решал, как это происходит на основе системы. Я попытался использовать серию переключателей, но это не совсем работает. Я знаю, что использование операторов if сложно для решателей на основе градиента, так что если есть какая-либо помощь, это было бы здорово, спасибо!

Capacity = 76.2
EStored = m.SV(value=0,lb=0,ub=Capacity)
batteryeff = .95
batteff = m.if3((Enuc - Cons),1/batteryeff,batteryeff)

#Energy Balance 
Cost = m.Var()
eneed = m.sign2(Enuc-Cons)  #gives sign of energy need for energy storage or removal from storage
eswitch = m.if3(eneed,0, 1) #Turns eneed into a binary switch
switch = m.if3(eswitch*(Capacity-EStored)+(1-eswitch)*(EStored),0,1) #supposed to charge battery until at capacity and then discharge until EStored is 0. Then use thermal energy second


m.Equation(EStored.dt() == (switch)*batteff*(Enuc - Cons))  #Energy balance for Battery
m.Equation(T.dt() == (1-switch)*thermeff*(Enuc - Cons)/(mass*Cp)) #Energy balance for Thermal Storage
m.Equation(Cost == Enuc*1000 )
m.Obj(Cost)

m.options.IMODE = 5
m.options.SOLVER = 3
m.solve()

Это раздел кода, с которым я работаю, однако, если более подробная информация Здесь необходим упрощенный вариант общего кода.

from gekko import GEKKO
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.integrate import quad

#Set up basic power consumption data
n = 24
t = np.linspace(0,n,n)
def load(t):
    return  -10*np.sin(2*np.pi*t/24)+40
Load = load(t)
Gen = np.ones(n)*40
def need(t):
    return 10*np.sin(2*np.pi*t/24)+10

#Set up Model
m = GEKKO()
m.time = t

Cons = m.Param(value=Load)
Enuc = m.FV(value=45, lb=0) #nuclear power
Enuc.STATUS = 1

#Thermal Energy Storage
T = m.SV(value=300,ub=500,lb=300)
mass = m.FV(value=.0746,lb=0)
mass.STATUS=0
Cp = m.Param(value=5)
thermaleff = .8   #80%efficient
thermeff = m.if3((Enuc - Cons)/(mass*Cp),1/thermaleff,thermaleff)

#Battery Electrical storage
Capacity = 76.2
EStored = m.SV(value=0,lb=0,ub=Capacity)
batteryeff = .95
batteff = m.if3((Enuc - Cons),1/batteryeff,batteryeff)

#Energy Balance 
Cost = m.Var()
eneed = m.sign2(Enuc-Cons)  #gives sign of energy need for energy storage or removal from storage
eswitch = m.if3(eneed,0, 1) #Turns eneed into a binary switch
switch = m.if3(eswitch*(Capacity-EStored)+(1-eswitch)*(EStored),0,1) #supposed to charge battery until at capacity and then discharge until EStored is 0. Then use thermal energy second


m.Equation(EStored.dt() == (switch)*batteff*(Enuc - Cons))  #Energy balance for Battery
m.Equation(T.dt() == (1-switch)*thermeff*(Enuc - Cons)/(mass*Cp)) #Energy balance for Thermal Storage
m.Equation(Cost == Enuc*1000 )
m.Obj(Cost)

m.options.IMODE = 5
m.options.SOLVER = 3
m.solve()

#plot
plt.subplot(3,1,1)
plt.plot(t,Load)
plt.plot(t,Enuc.value, label=f'Enuc = {Enuc.value[-1]}')
plt.ylabel("Energy")
plt.legend()

plt.subplot(3,1,2)
plt.plot(t,EStored.value, label=f'Capacity = {np.max(EStored.value):.03}')
plt.title("Battery Storage")
plt.ylabel("Energy")
plt.legend()

plt.subplot(3,1,3)
plt.plot(t,T.value,label=f'mass = {mass.value[-1]:.03}')
plt.title("Thermal Storage")
plt.ylabel("Temperature(K)")
plt.legend()
plt.show()```

1 Ответ

3 голосов
/ 29 апреля 2020

Вы можете использовать слабые переменные вместо условий переключения. Вот простая проблема с двумя баками и общим входным потоком 100. Входной поток можно разделить между двумя резервуарами, но максимальный объем резервуаров составляет 300 и 1000 соответственно. Резервуар 2 более дорогой в использовании (как и ваша система тепловой энергии).

Tank filling

import numpy as np
from gekko import GEKKO
m = GEKKO(remote=False)
m.time = np.linspace(0,10,100)
t = m.Var(0); m.Equation(t.dt()==1) # define time
flow = 100

V1 = m.Var(0,lb=0,ub=300) # tank 1
inlet1 = m.MV(0,lb=0); inlet1.STATUS = 1; inlet1.DCOST = 1e-4
m.Minimize(inlet1)

V2 = m.Var(0,lb=0,ub=1000) # tank 2
inlet2 = m.MV(0,lb=0); inlet2.STATUS = 1; inlet2.DCOST = 1e-4
m.Minimize(10*inlet2) # more expensive
                      # use tank 2 if tank 1 is projected to be filled

# only one in use, could also use inlet1*inlet2==0 to
#  enforce the complementarity condition
m.Minimize(inlet1*inlet2)

# mass balance
m.Equation(flow==inlet1+inlet2)
m.Equations([V1.dt()==inlet1,V2.dt()==inlet2])

m.options.IMODE = 6
m.solve(disp=False)

import matplotlib.pyplot as plt
plt.plot(m.time,inlet1.value,'r--',label='Inlet 1')
plt.plot(m.time,V1.value,'r-',label='Volume 1')
plt.plot(m.time,inlet2.value,'b--',label='Inlet 2')
plt.plot(m.time,V2.value,'b-',label='Volume 2')
plt.grid()
plt.legend()
plt.show()

Если оптимизатор знает, что накопление электрической и тепловой энергии будет заполняться тогда, это не обязательно имеет значение, когда они хранятся. Если вы хотите, чтобы логические условия обеспечивали прецедент, оператор m.if3() может быть лучше, но его также сложнее решить. Если вы можете заряжать электрическую и тепловую энергию одновременно, то средство обеспечения комплементарности m.Minimize(inlet1*inlet2) также не требуется и дает другое, но все же оптимальное решение.

continuous filling

В обоих случаях бак 1 является более дешевым вариантом, поэтому он достигнет емкости и сведет к минимуму заполнение бака 2. Это может быть лучшим решением для вашего случая, поскольку тогда вам не нужны условия переключения, которые могут вызвать проблемы. Аккумуляторная батарея будет полностью заполнена, но она может делать это одновременно с заполнением тепловой энергии, если прогноз состоит в том, что батарея будет заполняться в течение ночи, когда необходимо хранить электроэнергию.

...