Search code examples
pythonpandasnumpygekko

Error whilst running a state space equation using python GEKKO library


Attempting to model thermal losses from a building, I have implemented the following code to run the model using a state-space equation. It seems to take in variables as expected from .csv files and arrange them into correctly formed matrices. However, it is returning "Exception: Data arrays must have the same length, and match time discretization in dynamic problems". When trying to debug I printed all the matrices in the equations to see if they matched (see below). I feel like this should be easy to see but I don't know where I have gone wrong.

[[-9.15750916  9.15750916]
 [-0.12465719  0.13056645]]
[[295]
 [295]]
[[0.00000000e+00 7.38461538e+00 3.84615385e+00]
 [5.90925744e-03 0.00000000e+00 0.00000000e+00]]
[[[21.  14.  23.  28.  19. ]]

 [[ 1.5  1.2  1.4  1.7  2. ]]

 [[ 0.   0.   0.   0.   0. ]]]
[[1 0]]
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# SYSTEM BOUNDARIES
comfort = {'Occupied': np.array([20, 24])+273.15, \
           'Unoccupied': np.array([18, 26])+273.15}  
build_type = {'detached':np.array([0.42,0.26,8.86,19.1,1.92]),\
             'semi-detached':np.array([]),\
             'end-terrace':np.array([]),\
             'mid-terrace':np.array([]),\
             'bungalow':np.array([]),\
             'flat':np.array([])}
# get csv data
# datafile = ""
df = pd.read_csv(r"COP_test.csv")
# sort data by column names
x0 = np.array(df["Ta"]) # Ambient temp
x1 = np.array(df["Ih"]) # Solar radiation
x2 = np.array(df["Qo"]) # Additional heating influences
#GEKKO model and initialise model simulator
m = GEKKO(remote=False); m.options.IMODE=4
# Building temperature variables
T_int = m.FV(295, lb=18+273.15, ub=24+273.15)
T_wal = m.FV(295, lb=15+273.15, ub=30+273.15)
# independent variables
Q_ext = m.Array(m.Param,3); Q_ext[0].value=x0; Q_ext[1].value=x1; Q_ext[2].value=x2, 
# building coefficients
R_int, C_int, R_wal, C_wal, gA = build_type[btype]
# Matrix equations
A = np.array([[-1/(R_int*C_int), 1/(R_int*C_int)],
              [-1/(R_int*C_wal), -(-1/(R_wal*C_wal)-1/(R_int*C_wal))]])
Bc = 1/C_int
Bx = np.array([[0, gA/C_int, 1/C_int],
              [1/(R_wal*C_wal), 0, 0]])
C = np.array([[1, 0]])
# [T_int.dt(), T_wal.dt()] = m.equations()
x, y, u = m.state_space(A,Bx,C,D=None,discrete=True)
# right now does not include Bc, could append into matrix Bx
u[0].value = np.array([[x0],[x1],[x2]])
x[0].value = np.array([[T_int],[T_wal]])
print(A, x[0].value, Bx, u[0].value, C, sep='\n')
m.time = np.linspace(0,24,len(x0)) # time points, ideally to have a reading every half hour
m.options.nodes = 4
m.solve() # (GUI=True)

Solution

  • The code needed some modifications to import the data but the model was good. The script was also missing the data file and the btype variable. Here is some sample data for testing with data.csv.

    time,Ta,Ih,Qo
    0,30,0,0
    4,31,0,0
    8,35,10,20
    12,38,20,30
    16,40,50,20
    20,37,30,10
    24,30,0,0
    

    On future questions, please include a complete example. Here is the modified code. I've commented out the state constraints because those can lead to an infeasible solution. You also need to use m.options.NODES=2 for discrete state space models.

    from gekko import GEKKO
    import numpy as np
    import matplotlib.pyplot as plt
    import pandas as pd
    # SYSTEM BOUNDARIES
    comfort = {'Occupied': np.array([20, 24])+273.15, \
               'Unoccupied': np.array([18, 26])+273.15}  
    build_type = {'detached':np.array([0.42,0.26,8.86,19.1,1.92]),\
                 'semi-detached':np.array([]),\
                 'end-terrace':np.array([]),\
                 'mid-terrace':np.array([]),\
                 'bungalow':np.array([]),\
                 'flat':np.array([])}
    # get csv data
    df = pd.read_csv(r"test.csv")
    btype = 'detached'
    #GEKKO model and initialise model simulator
    m = GEKKO(remote=False); m.options.IMODE=4
    
    T_int = m.FV(295, lb=18+273.15, ub=24+273.15)
    T_wal = m.FV(295, lb=15+273.15, ub=30+273.15)
    
    # building coefficients
    R_int, C_int, R_wal, C_wal, gA = build_type[btype]
    # Matrix equations
    A = np.array([[-1/(R_int*C_int), 1/(R_int*C_int)],
                  [-1/(R_int*C_wal), -(-1/(R_wal*C_wal)-1/(R_int*C_wal))]])
    Bc = 1/C_int
    Bx = np.array([[0, gA/C_int, 1/C_int],
                  [1/(R_wal*C_wal), 0, 0]])
    C = np.array([[1, 0]])
    # State Space
    x, y, u = m.state_space(A,Bx,C,D=None,discrete=True)
    # right now does not include Bc, could append into matrix Bx
    Ta,Ih,Qo = u
    # Building temperature variables
    T_int,T_wal = x
    T_int.value = 295
    T_wal.value = 295
    
    # Bounds on states can make the problem infeasible
    #T_int.lower = 18+273.15
    #T_int.upper = 24+273.15
    #T_wal.lower = 15+273.15
    #T_wal.upper = 30+273.15
    
    # steady-state initialization
    #m.options.IMODE = 1 
    #m.solve() # (GUI=True)
    
    # dynamic simulation
    m.time = df['time'] # time points
    m.options.nodes = 2 # must be 2 for discrete models
    Ta.value = df["Ta"] # Ambient temp
    Ih.value = df["Ih"] # Solar radiation
    Qo.value = df["Qo"] # Additional heating influences
    m.solve()
    

    There are additional state space examples in the documentation, including a complete MPC application with an Arduino microcontroller.