#!/usr/bin/env python
################################################################################
# Copyright 2015 Brecht Baeten
# This file is part of mpcpy.
#
# mpcpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# mpcpy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with mpcpy. If not, see <http://www.gnu.org/licenses/>.
################################################################################
import sys
import numpy as np
[docs]class Boundaryconditions(object):
"""
A class to define boundaryconditions in the format required by mpcpy.
"""
def __init__(self,data,periodic=True,extra_time=7*24*3600.,zoh_keys=None):
"""
Create a boundaryconditions object.
Parameters
----------
data : dict
Actual boundary conditions and a time vector.
periodic : boolean, optional
Determines how to determine values when time is larger than the
boundary conditions time.
extra_time : float, optional
Maximum allowed time outside the boundary conditions time, should be
at least as large as the control horizon.
zoh_keys : list of strings, optional
Keys which will be interpolated with zero-order hold. All other
values are interpolated linearly.
Examples
--------
>>> bcs = Boundaryconditions({'time': np.arange(0.,24*3600.+1,3600.), 'T_amb':np.random.random(25)})
>>> bcs(12.1*3600)
"""
self.data = {}
# create a new time vector including the extra time
# this method is about 2 times faster than figuring out the correct time during interpolation
ind = np.where( data['time']-data['time'][0] < extra_time )[0]
self.data['time'] = np.concatenate((data['time'][:-1],data['time'][ind]+data['time'][-1]-data['time'][0] ))
if periodic:
# the values at time lower than extra_time are repeated at the end of the dataset
# extra_time should thus be larger than the control horizon
for key in data:
if key != 'time':
self.data[key] = np.concatenate((data[key][:-1],data[key][ind]))
else:
# last value is repeated after the actual data
for key in data:
if key != 'time':
self.data[key] = np.concatenate((data[key][:-1],data[key][-1]*np.ones(len(ind))))
if zoh_keys is None:
self.zoh_keys = []
else:
self.zoh_keys = zoh_keys
[docs] def interp(self,key,time):
"""
Interpolate a value to an array of timesteps
Parameters
----------
key : str
The key to interpolate.
time : np.array
An array of times to interpolate to.
"""
if len(np.array(self.data[key]).shape) == 1:
if key in self.zoh_keys:
value = interp_zoh(time,self.data['time'],self.data[key])
else:
value = np.interp(time,self.data['time'],self.data[key])
elif len(np.array(self.data[key]).shape) == 2:
# 2d boundary conditions support
value = np.zeros((len(time),self.data[key].shape[1]))
if key in self.zoh_keys:
for j in range(self.data[key].shape[1]):
value[:,j] = interp_zoh(time,self.data['time'],self.data[key][:,j])
else:
for j in range(self.data[key].shape[1]):
value[:,j] = np.interp(time,self.data['time'],self.data[key][:,j])
else:
raise Exception('Only 1D or 2D data allowed as boundary conditions')
return value
[docs] def __call__(self,time):
"""
Return the interpolated boundary conditions
Parameters
----------
time : number or np.array
true value for time
Returns
-------
dict
Dictionary with interpolated boundary conditions.
"""
bcs_int = {}
for key in self.data:
bcs_int[key] = self.interp(key,time)
return bcs_int
def __getitem__(self,key):
return self.data[key]
def has_key(self, key):
return self.data.has_key(key)
def __contains__(self, item):
return item in self.data
def __iter__(self):
return self.data.__iter__()
def interp_zoh(x,xp,fp):
"""
Interpolate with zero order hold
Parameters
----------
x : np.array
An array of independent variables where the values are required.
xp : np.array
An array of independent variables where the values are known, must be
monotonic and increasing.
fp : np.array
The known values at points xp.
Returns
-------
np.array
The interpolated values
"""
return np.array([fp[int((len(xp)-1)*(xi-xp[0])/(xp[-1]-xp[0]))] for xi in x])