Source code for mpcpy.disturbances

#!/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 numpy as np


[docs]class Disturbances(object): """ A class to define disturbances in the format required by mpcpy. """ def __init__(self, data, periodic=True, extra_time=7*24*3600., zoh_keys=None): """ Create a disturbances 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 -------- >>> dst = Disturbances({'time': np.arange(0.,24*3600.+1,3600.), 'T_amb':np.random.random(25)}) >>> dst(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. """ dst_int = {} for key in self.data: dst_int[key] = self.interp(key, time) return dst_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])