Gekko MPC controller - update parameters at each time step - gekko

I am working on an MPC problem with individual linear models predicting the control variable at each time step in the prediction horizon (see below where u is the manipulated variable and y is the control variable). The coefficients of each linear model in the prediction horizon change based on the current state variables each time the window moves.
y[i+1] = A[i]#u[i]+B[i]
y[i+2] = A[i+1]#u[i:i+2]+B[i+1]
...
y[i+n] = A[i+n-1]#u[i:i+n]+B[i+n-1]
A and B are a list of matrices which are determined from a function of the current state. I basically want to pause the controller at the beginning of each time step (prior to optimization) and recalculate these coefficient matrices based on the feedback from the system. Is it possible to do this in Gekko using MPC mode (IMODE=6) or do I need to manage the time outside of Gekko?

You can do it by running both MHE and MPC in a row. You want to run MHE(imode=5) at every time step to estimate the model parameters A and B. Then, update the MPC model with the new A and B before executing the MPC(mode=6) calculation.
Here is an example of TCLab temperature control using combined MHE and MPC.
https://apmonitor.com/do/index.php/Main/TCLabH
You might need to change the model in this example with an ARX type of model that you can find on this page.
https://apmonitor.com/do/index.php/Main/NonlinearControl

This is for your follow-up question in the comment.
Just for clarification, does the ARX model structure for MPC prediction change throughout all simulation time steps? Or, does it only happen at the beginning of the simulation when you don't have enough past data?
If the latter is your case, GEKKO will automatically handle it for you.
This is the structure of the ARX model.
na: # of the coefficient for CV
nb: # of the coefficient for MV
nk: Length of a time-delay between CV and MV
Gekko automatically adjusts the na and nb for the beginning of the simulation when t < na or t < nb, which turns out the same formula in your original question above.

Related

How can I get Results faster for my MINLP Optimization with APM GEKKO?

I am trying to do an Optimization for the Energy Supply of an domestic House. The energy demand should be satisfied by a Heat Pump, PV-Modules, Electric Water Heater and the public electricity Grid. Also the Energy System consists of an Battery Storage an a Heat Storage. The only (binary) integer Variable in my Program is the Heat Pump. My Goal is to Optimize the System over the Timeframe of 1 Year (8760 timesteps). When I run the Code with 1800 timesteps I get results in about 500 seconds. For 4500 timestamps it already takes about 9 Hours. For the full 8760 timesteps the code is still running (since about 24 Hours) without any solution. In earlier iterations of the code it ran for more than a Week without generating results. I already tried a few things I read here to speed up the optimization. Is there anyway I can get the Program to find a solution faster? Since I am a beginner at Python it is very much possible that my Code is inefficient. I would very much appreciate it, if someone has an Idea that can get me faster Results or estimate the time the program takes to find a solution. Thank you very much in advance.
Here is my Code, I have shortened the Arrays for the Energy-Demand to 100 Values to shorten my Code:
from gekko import GEKKO
import numpy as np
import matplotlib.pyplot as plt
timesteps= 100
m = GEKKO(remote=False)
t = np.linspace(0, timesteps-1, timesteps) #Zeit
m.time = t
m.options.SOLVER = 1
m.options.IMODE = 6
m.options.NODES = 2
m.options.REDUCE=3
m.solver_options = ['minlp_maximum_iterations 1000',\
'minlp_max_iter_with_int_sol 1000',\
'minlp_integer_tol 1.0e-1',\
'minlp_branch_method 1',\
'objective_convergence_tolerance 1.0e-4',\
'minlp_gap_tol 9e-1']
# Energy Demand
#1. electricity
EL_Demand_Arr1=np.array([1.9200000,1.4890000,1.4920000,1.1300000,0.64099997,0.58600003,0.58399999,0.61000001,0.54900002,0.59500003,0.92699999,0.95599997,0.91000003,1.1450000,1.1090000,1.6360000,1.4740000,1.4680001,2.6150000,2.1810000,1.2320000,1.3700000,0.96899998,1.3220000,1.1880000,0.64399999,0.53899997,0.55299997,0.52899998,0.56099999,0.54600000,0.80000001,1.1350000,0.70700002,1.1680000,1.0440000,2.3160000,1.6420000,2.2370000,2.8870001,1.8550000,1.4030000,0.70599997,1.4980000,3.4879999,1.5130000,1.4349999,1.3520000,1.0530000,0.51700002,0.55000001,0.52800000,0.52999997,0.56199998,0.53700000,0.58999997,0.53500003,0.92500001,1.3490000,0.66299999,4.3810000,1.0200000,0.79799998,0.77899998,1.0840000,2.1530001,3.7449999,5.3490000,1.8710001,2.3610001,0.78799999,0.47099999,0.56800002,0.51700002,0.54799998,0.55699998,0.51400000,0.56500000,3.2790000,2.2750001,1.2300000,0.97899997,0.78200001,1.0140001,0.77800000,0.58099997,0.52999997,0.55900002,1.1770000,1.5400000,1.4349999,2.0400000,2.2790000,1.6520000,1.6450000,1.2830000,0.55800003,0.52499998,0.51899999,0.53799999])
EL_Demand_Arr2=EL_Demand_Arr1.round(decimals=3)
EL_Demand_Arr=EL_Demand_Arr2[0:timesteps]
EL_Demand=m.Param(EL_Demand_Arr,name='EL_Demand')
#2. heat
H_Demand_Arr1=np.array([1.0960000,1.0790000,1.1590000,1.1760000,1.6940000,2.2639999,2.1450000,2.0769999,2.0720000,2.0300000,1.9069999,1.8810000,1.7880000,1.8180000,1.8049999,2.0430000,2.1489999,2.1700001,2.1830001,2.1910000,1.9920000,1.5290000,1.1810000,1.0400000,1.4310000,1.4110000,1.4700000,1.4900000,1.8880000,2.4530001,2.2809999,2.3199999,2.2960000,2.3299999,2.1630001,2.1289999,2.0599999,2.1090000,2.0940001,2.3450000,2.4380000,2.4679999,2.4630001,2.4480000,2.2219999,1.8480000,1.5779999,1.4310000,1.5000000,1.4790000,1.5410000,1.5620000,1.9790000,2.5720000,2.3910000,2.4319999,2.4070001,2.4430001,2.2679999,2.2309999,2.1589999,2.2110000,2.1949999,2.4579999,2.5560000,2.5869999,2.5820000,2.5660000,2.3290000,1.9380000,1.6540000,1.5000000,1.7160000,1.6930000,1.7630000,1.7869999,2.2650001,2.9430001,2.7360001,2.7839999,2.7539999,2.7950001,2.5950000,2.5539999,2.4710000,2.5300000,2.5120001,2.8130000,2.9250000,2.9600000,2.9549999,2.9370000,2.6659999,2.2170000,1.8930000,1.7160000,1.7980000,1.7670000,1.8789999,1.9160000])
H_Demand_Arr2=H_Demand_Arr1.round(decimals=3)
H_Demand_Arr=H_Demand_Arr2[0:timesteps]
H_Demand=m.Param(H_Demand_Arr,name='H_Demand')
#3. Domestic Hot Water
DHW_Demand_Arr1=np.array([1.7420000,0,0,2.0320001,0,0,3.7739999,2.4960001,3.3670001,0,2.4380000,1.1030000,0,0,0,3.1350000,2.2060001,0,4.4120002,0,0,0,0.87099999,1.5089999,0,0,0,0,0,0.87099999,0.81300002,1.1610000,2.5539999,1.6260000,0,0,0.63900000,0,3.4830000,2.8450000,2.4960001,7.1409998,5.7480001,2.3800001,3.1930001,0,1.1610000,0,0,0,0,0,0,0,2.6129999,1.9160000,4.2379999,0.34799999,5.4569998,0,0,2.8450000,0,0,0,0,0,2.4960001,1.6260000,0,2.5539999,0,0,0,0,0,1.6260000,0,3.0190001,0,2.8450000,1.1030000,2.9030001,0,0,0,0.98699999,0,1.1610000,0.34799999,1.3930000,1.2770000,4.4120002,0,0,0,0,1.8580000,0,0.98699999])
DHW_Demand_Arr2=DHW_Demand_Arr1.round(decimals=3)
DHW_Demand_Arr=DHW_Demand_Arr2[0:timesteps]
DHW_Demand=m.Param(DHW_Demand_Arr,name='TWW_BED')
#4. electricity production from PV
PV_P_Arr1=np.array([0,0,0,0,0,0,0,0,0,0.057000000,0.14399999,0.30500001,0.13600001,0.28900000,0.22000000,0.0040000002,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.061999999,0.78899997,0.56300002,0.13600001,0.052999999,0.017000001,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.037000000,0.098999999,0.15000001,0.11200000,0,0.12600000,0.032000002,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0040000002,0.73600000,1.8250000,2.4020000,3.1870000,0.66500002,0.045000002,0,0,0,0,0,0,0,0,0,0,0,0,0])
PV_P_Arr2=PV_P_Arr1.round(decimals=3)
PV_P_Arr=PV_P_Arr2[0:timesteps]
PV_P=m.Param(PV_P_Arr,name='PV_P')
# Heat Pump "Bit" ist '1' during the Heating Season and '0' outside the heating Season to tell the Promgram that the Heat Pump may only be used during heating Season
HP_Bit_Arr1=np.array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1])
HP_Bit_Arr=HP_Bit_Arr1[0:timesteps]
HP_Bit=m.Param(HP_Bit_Arr,name='HP_Bit')
# Battery Storage
B_S = m.SV(0,lb=0)
B_S.FSTATUS=1
m.fix_initial(B_S,0)
B_S_Load = m.SV(0,lb=0) #Loading Battery
B_S_Recover = m.SV(0,lb=0) #Recover Energy from Batterie
eff_B_S = 0.95 #efficiency Battery
# Heat Storage
H_S = m.SV(0,lb=0)
H_S.FSTATUS=1
m.fix_initial(H_S,0)
H_S_Load = m.SV(lb=0) #Loading Heat Storage
H_S_Recover = m.SV(lb=0) #Recover Energy from Heat Storage
eff_H_S = 0.9 #efficiency Heat Storage
#Heat Pump
# Binary Variable for Heat Pump (it can either be turned on '1' or off '0')
P_HP_Binary=HP_Bit*m.sos1([0,1])
P_HP_Binary.STATUS = 1
#Electrical sizing of the Heat Pump
P_el_HP1= m.SV(0,lb=0)
P_el_HP1.FSTATUS=1
#Electrical Water Heater
EH=m.SV(0,lb=0)
EH.FSTATUS=1
# The Power of the Heat Pump multiplied with the Binary Variable gives the actual Output of the Heat Pump
P_el_HP=m.Intermediate(P_HP_Binary*P_el_HP1)
COP_HP=3.5 #COP of the Heat Pump
Q_HP=m.Intermediate(COP_HP*P_el_HP) # thermal Energy Output of the Heat Pump
# the objective of this Optimization ist to minimize the Cost for the Energy-System, scince you only Pay for the maximal Value of the Heat Pump, Energy Storages and the electrical Water Heater and not for the value at each timestep, I define a FV that describes the maximal Value of the Components
P_el_HP_max=m.FV(lb=0) #Heat Pump
P_el_HP_max.STATUS=1
H_S_max=m.FV(lb=0) #Heat Storage
H_S_max.STATUS=1
B_S_max=m.FV(lb=0) #Battery
B_S_max.STATUS=1
EH_max=m.FV(lb=0) #Electrical Water Heater
EH_max.STATUS=1
# We have energy Production from PV, there ist a possibility to give Energy thats not needed to the public Grid
I_Excess=m.Var(0,lb=0)
# In Case we have more Demand for Electrical Enery than Production from PV we have the possibility to get Energy from the public Grid
I_feed_out=m.SV(0,lb=0)
I_feed_out.FSTATUS=1
# Volume of the Heat Storage in m^3
Vol_HS=m.Intermediate((H_S_max*3600)/(1000*4.18*(35-10)))
# boundary conditions
m.Equations([PV_P +I_feed_out + B_S_Recover - P_el_HP - B_S_Load - I_Excess - EH == EL_Demand, #Energy Balance needs to satisfy the Demand
B_S.dt() == B_S_Load - B_S_Recover/eff_B_S, #Loading and Recovery of the Battery
B_S_Load * B_S_Recover == 0, #It is not allowed to Load and Recover at the same Time, at least one of both needs to be equal to '0' at each Timestep
P_el_HP*COP_HP + H_S_Recover - H_S_Load + EH == H_Demand + DHW_Demand, #The Demand of Heat and DHW needs to be satisfied at each timestep
H_S.dt() == H_S_Load - H_S_Recover/eff_H_S, #Loading and recovery of the Heat Storage
H_S_Load * H_S_Recover == 0, #It is not allowed to Load and Recover at the same Time, at least one of both needs to be equal to '0' at each Timestep
# The maximal Value of the Enery System Components is the Upper Bound for the Value at each time Step
P_el_HP1 <= P_el_HP_max,
P_el_HP1 >= 0.4*P_el_HP_max, # the Heat Pump is a variable speed heat Pump and has a minimal output of 40% of the nominal Power
H_S <= H_S_max,
B_S <= B_S_max,
EH <= EH_max,])
#Objective is to minimize the cost of the Energy System (the Cost of Components that only need to be bought once get divided by the number of timesteps)
Objective=(((P_el_HP_max*1918.4)*P_el_HP_max+(EH_max*50)+B_S_max*1664.9*B_S_max+(Vol_HS*2499.3*Vol_HS))/(20*timesteps)-0.05*I_Excess+0.35*(I_feed_out))
m.Minimize(Objective)
m.solve(disp=True)
#Print Results
print("Nominal Power of the Heat Pump=",max(P_el_HP),"kW")
print("maximum Capacity of the Heat Storage=",max(H_S),"kW")
print("Volume of the Heat Storage=", max(Vol_HS),"m^3")
print("maximum Capacity of the Battery", max(B_S),"kW")
print("Electricity from the Public Grid",sum(I_feed_out[0:timesteps-1]))
# Plot results
fig, axes = plt.subplots(6, 1, figsize=(5, 5.1), sharex=True)
axes = axes.ravel()
ax = axes[0]
ax.plot(t, EL_Demand, 'r-', label='Electrical Demand',lw=1)
ax.plot(t, PV_P,'b:', label='PV Production',lw=1) #z.B. Generator (haben wir aber in unserem Energiesystem nicht)
ax = axes[1]
ax.plot(t, EL_Demand, 'r-', label='Electrical Demand',lw=1)
ax.plot(t,I_feed_out, 'k--', label='Electricity from the public Grid',lw=1)
ax = axes[2]
ax.plot(t,B_S.value, 'k-', label='Battery Storage',lw=1)
ax.plot(t,B_S_Load,'g--',label='Battery Storage Loading',lw=1)
ax.plot(t,B_S_Recover,'b:',label='Battery Storage Recovery',lw=1) #lw=2 --> linewidth
ax = axes[3]
ax.plot(t,H_Demand, 'r-', label='Heat Demand',lw=1)
ax.plot(t, Q_HP.value,'b:',\
label='Thermal Production Heat Pump',lw=1)
ax = axes[4]
ax.plot(t,H_S, 'k-', label='Heat Storage',lw=1)
ax.plot(t,H_S_Load,'g--',label='Heat Storage Loading',lw=1)
ax.plot(t,H_S_Recover.value,'b:',\
label='Heat Storage Recovered Energy',lw=1)
ax = axes[5]
ax.plot(t,DHW_Demand, 'r-', label='Domestic Hot Water Demand',lw=1)
ax.plot(t, EH,'b:',\
label='Electrical Water Heater',lw=1)
for ax in axes:
ax.legend(loc='center left',\
bbox_to_anchor=(1,0.5),frameon=False)
ax.grid()
ax.set_xlim(0,len(t)-1)
plt.savefig('Results.png', dpi=600,\
bbox_inches = 'tight')
plt.show()
The scale-up issue is likely with the heat pump binary variable. An exhaustive search for your cases leads to the evaluation of 2^8760 possible solutions. The APOPT solver uses a branch and bound method that greatly reduces the number of potential solution candidates. Here are solver options that are recommended to improve the speed and control the solution tolerance.
m = GEKKO()
m.solver_options = ['minlp_gap_tol 0.1',\
'minlp_maximum_iterations 1000',\
'minlp_max_iter_with_int_sol 500',\
'minlp_branch_method 1',\
'nlp_maximum_iterations 100']
m.options.solver = 1
minlp_maximum_iterations - maximum number of NLP solutions from the branch and bound method. A successful solution is returned if there is an integer solution upon reaching the maximum number of iterations. Otherwise, the solution is not considered to be successful and an error message is returned with the failed solution.
minlp_max_iter_with_int_sol - maximum number of NLP solutions when a candidate integer solution is found
minlp_gap_tol: gap is the spread between the lowest candidate leaf (obj_r=non-integer solution) and the best integer solution (obj_i). When the gap is below the minlp_gap_tol, the best integer solution is returned
minlp_branch_method: 1=depth first (find integer solution faster), 2=breadth first, 3=lowest objective leaf, 4=highest objective leaf
nlp_maximum_iterations: maximum number of iterations for each NLP sub-problem. Reducing the NLP maximum iterations can improve the solution speed because less computational time is spent on candidate solutions that may not converge
I recommend fine-tuning these solver options on a short time horizon problem, perhaps 100 time steps to solve in a few seconds. The improvement in computational speed should also apply for the larger problems.
There are excellent suggestions in the other answer posted on tweaking GEKKO, which I'm not too familiar with, but the main issue you have is that you've made a non-linear model, which will be extraordinarily difficult to solve over that many time periods. I'd strongly suggest:
Reformulate. You can very likely make this linear. You are multiplying variables together in several places, which makes the model non-linear. There are linear formulations that could be substituted. Find them all and fix them, even if you have to add more variables. You might be able to make this a simple LP (no integer requirements) and it would solve in a snap. For instance, you do not need to multiply the binary heat pump variable by the heat pump output to regulate that. That is non-linear. You should just be doing something like:
heat_pump_output[t] <= heat_pump_max_output * heat_pump_on[t]
where heat_pump_max_output is a fixed parameter (optionally time-indexed) and heat_pump_on[t] is either a parameter limiting on times or a binary variable, if needed.
There are several other parts that might be changed also, such as charge-discharge where you have 2 variables and might consider just one "flow" variable that can be positive or negative. (This might be tough if you have different "efficiencies" for charging/discharging.)
There are also ways to linearize "or" conditions if that (above) doesn't work or if there are other needs with binary variables without multiplication.
Review your objective for non-linearities also. It is unclear why you are squaring variables in your objective function when you are looking at costs
If the above is unsuccessful and you cannot linearize the model, then think about not solving for all time steps at once or just pick a much larger time step, perhaps aggregated to 6 observations a day at "stressful" times.
Here is a highly similar model written in pulp that solves in about 30 seconds for 8000+ time steps. Translation into GEKKO shouldn't be too daunting if you like that framework.

Exogenous variables in hmmlearn's GaussianHMM

I am trying to use hmmlearn's GaussianHMM to fit a Hidden Markov Model with 2 main states, while allowing for multiple exogenous variables. My goal is to determine two states of GDP growth (one with low variance and the other with high variance), these states then depend on lagged unemployment, lagged commercial confidence level etc. I have a couple of questions:
Using hmmlearn's GaussiansHMM, I have read through the documentation but I cannot find any mention of exogenous variable. Using the method fit(X, lengths=None), I see that X can have n_features columns, do I understand correctly that I should pass in an array with the first column being the endogenous varible (GDP growth in my case) and the rest of columns are the exogenous variables ?
Is hmmlearn's GaussianHMM equivalent to statsmodels.tsa.regime_switching.markov_regression.MarkovRegression ? This model allows for exog_tvtp which means that exogenous variables are used to calculate a time varying transition probabilities matrix.
An example of fitting the monthly returns of the S&P500, no exogenous variable.
import numpy as np
import pandas as pd
from hmmlearn.hmm import GaussianHMM
import yfinance as yf
sp500 = yf.download("^GSPC")["Adj Close"]
# Fitting an absolute return model because we only care about volatility #
rets = np.log(sp500/sp500.shift(1)).dropna()
rets.index = pd.to_datetime(rets.index)
rets = rets.resample("M").sum()
model = GaussianHMM(n_components=2)
model.fit(rets.to_frame())
state_sequence = model.predict(rets.to_frame())
Imagine if I want to add a dependency on exogenous variables to the returns of the S&P500, for example on economic growth or past volatilities, is there a way to do this ?
Thanks for any help.
n_features can be thought of as the temporal domain, and should not be conflated with features that describe the complexity of ie. a regression model.
If your hidden states are the two states of GDP growth, then the observed variable (or emissions) that you are trying to infer the hidden states from should be the feature space (a.k.a. n_features).
This should be a single measurement (emission) descriptive of a combination of your "exogenous variables", collected over time. hmmlearn will not be able to take multivariate emissions.
Suggestions
If I understand your question correctly, perhaps what you might be looking for are Kalman filters. KF produces estimates of unknowns based on multiple measurements (ie. all of your exogenous variables) that ultimately produce a model more accurate than those based on a single measurement.
If you wish each hidden state to have multiple independent emissions then what you might be looking for is a structured perceptron. This is discussed here: Hidden Markov Model for multiple observed variables

Questions about feature selection and data engineering when using H2O autoencoder for anomaly detection

I am using H2O autoencoder in R for anomaly detection. I don’t have a training dataset, so I am using the data.hex to train the model, and then the same data.hex to calculate the reconstruction errors. The rows in data.hex with the largest reconstruction errors are considered anomalous. Mean squared error (MSE) of the model, which is calculated by the model itself, would be the sum of the squared reconstruction errors and then divided by the number of rows (i.e. examples). Below is some sudo code of the model.
# Deeplearning Model
model.dl <- h2o.deeplearning(x = x, training_frame = data.hex, autoencoder = TRUE, activation = "Tanh", hidden = c(25,25,25), variable_importances = TRUE)
# Anomaly Detection Algorithm
errors <- h2o.anomaly(model.dl, data.hex, per_feature = FALSE)
Currently there are about 10 features (factors) in my data.hex, and they are all categorical features. I have two questions below:
(1) Do I need to perform feature selection to select a subset of the 10 features before the data go into the deep learning model (with autoencoder=TRUE), in case some features are significantly associated with each other? Or I don’t need to since the data will go into an autoencoder which compresses the data and selects only the most importance information already, so feature selection would be redundant?
(2) The purpose of using the H2O autoencoder here is to identify the senders in data.hex whose action is anomalous. Here are two examples of data.hex. Example B is a transformed version of Example A, by concatenating all the actions for each sender-receiver pair in Example A.
After running the model on data.hex in Example A and in Example B separately, what I got is
(a) MSE from Example A (~0.005) is 20+ times larger than MSE from Example B;
(b) When I put the reconstruction errors in ascending order and plot them (so errors increase from left to right in the plot), the reconstruction error curve from Example A is steeper (e.g. skyrocketing) on the right end, while the reconstruction error curve from Example B increases more gradually.
My question is, which example of data.hex works better for my purpose to identify anomalies?
Thanks for your insights!
Question 1
You shouldn't need to decrease the number of inputted features into the model. I can't say I know what would happen during training, but collinear/associated features could be eliminated in the hidden layers as you said. You could consider adjusting your hidden nodes and see how it behaves. hidden = c(25,25,25) -> hidden = c(25,10,25) or hidden = c(15,15) or even hidden = c(7, 5, 7) for your few features.
Question 2
What is the purpose of your model? Are you trying to determine which "Sender/Receiver combinations" are anomalies or are you trying to determine which "Sender/Receiver + specific Action combo" are anomalies? If it's the former ("Sender/Receiver combinations") I would guess Example B is better.
If you want to know "Sender/Receiver combinations" and use Example A, then how would you aggregate all the actions for one Sender-Receiver combo? Will you average their error?
But it sounds like Example A has more of a response for anomalies in ascended order list (where only a few rows have high error). I would sample different rows and see if the errors make sense (as a domain expert). See if higher errors tend to seem to be anomaly-like rows.

How to deal with discrete time system in GEKKO?

I am dealing with a discrete time system with sampling time of 300s.
My question is that how to express the state equation or output eqatuin like
x(k+1)=A*x(k)+B*u(k)
y(k)=C*x(k)
where x(k) is the state and y(k) is the output. I have all the value of A, B, C matrix.
I found some information about discrete time system on webpage https://apmonitor.com/wiki/index.php/Apps/DiscreteStateSpace
I want to know whether there is another way to express state equation other than
x,y,u = m.state_space(A,B,C,D=None,discrete=True)
The discrete state space model is the preferred way to pose your model. You could also convert your equations to a discrete time series form or to a continuous state space form. These all are equivalent forms. Another way to write your model is to use IMODE=2 (algebraic equations) but this is much more complicated. Here is an example of MIMO identification where we estimate ARX parameters with IMODE=2. I recommend the m.state_space model and to use it with IMODE>=4.
Here is a pendulum state space model example.
and a flight control state space model.
These both use continuous state space models but the methods are similar to what is needed for your application.

How to include measurement bias correction in GEKKO for model predictive control MPC?

I need to include the bias correction term in my MPC calculation. This is the difference between model predictions and measurements at each time instant. How to specify in GEKKO?
GEKKO has a tuning parameter called BIAS that should give you what you want. To quote from the GEKKO documentation on BIAS:
BIAS is additive factor that incorporates the difference between the current measured value and the initial condition of the controller. FSTATUS determines how much of the raw measurement is used to update the value of MEAS. A feedback status of 0 indicates that the measurement should not be used and the BIAS value is kept at the initial value of 0. A feedback status of 1 uses all of the measurement in updating MEAS. A feedback status in between 0 and 1 updates MEAS with a fractional contribution from LSTVAL and the new measurement. The value of BIAS is updated from MEAS and the unbiased model prediction (Model_u).
BIAS = MEAS − Model_u
The BIAS is added to each point in the horizon and the controller objective function drives the biased model (Model_b) to the requested set point range.
Model_b = Model_u + BIAS
The value of BIAS can also be set to an external value by setting the option BIAS option directly and setting FSTATUS to 0 (OFF).
So if you want to automatically align your model predictions with your measured values, set the feedback status to 1 for each CV in your model (model_name.variable_name.FSTATUS = 1).
You can also compute the bias correction term yourself each time you have a new measurement by subtracting the predicted value from the prior MPC cycle at the appropriate time step from the corresponding new measurement.

Resources