-
Notifications
You must be signed in to change notification settings - Fork 458
Expand file tree
/
Copy pathbasis.py
More file actions
142 lines (111 loc) · 4.25 KB
/
Copy pathbasis.py
File metadata and controls
142 lines (111 loc) · 4.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# basis.py - BasisFamily class
# RMM, 10 Nov 2012
"""Define base class for implementing basis functions.
This module defines the `BasisFamily` class that used to specify a set
of basis functions for implementing differential flatness computations.
"""
import numpy as np
# Basis family class (for use as a base class)
class BasisFamily:
"""Base class for basis functions for flat systems.
A BasisFamily object is used to construct trajectories for a flat system.
The class must implement a single function that computes the jth
derivative of the ith basis function at a time t:
:math:`z_i^{(q)}(t)` = basis.eval_deriv(self, i, j, t)
A basis set can either consist of a single variable that is used for
each flat output (nvars = None) or a different variable for different
flat outputs (nvars > 0).
Parameters
----------
N : int
Order of the basis set.
Attributes
----------
nvars : int or None
Number of variables represented by the basis (possibly of different
order/length). Default is None (single variable).
coef_offset : list
Coefficient offset for each variable.
coef_length : list
Coefficient length for each variable.
"""
def __init__(self, N):
"""Create a basis family of order N."""
self.N = N # save number of basis functions
self.nvars = None # default number of variables
self.coef_offset = [0] # coefficient offset for each variable
self.coef_length = [N] # coefficient length for each variable
def __repr__(self):
return f'<{self.__class__.__name__}: nvars={self.nvars}, ' + \
f'N={self.N}>'
def __call__(self, i, t, var=None):
"""Evaluate the ith basis function at a point in time."""
return self.eval_deriv(i, 0, t, var=var)
def var_ncoefs(self, var):
"""Get the number of coefficients for a variable.
Parameters
----------
var : int
Variable offset.
Returns
-------
int
"""
return self.N if self.nvars is None else self.coef_length[var]
def eval(self, coeffs, tlist, var=None):
"""Compute function values given the coefficients and time points.
Parameters
----------
coeffs : array
Basis function coefficient values.
tlist : array
List of times at which to evaluate the function.
var : int or None, optional
Number of independent variables represented using the basis.
If None, then basis represents a single variable.
Returns
-------
array
Values of the variable(s) at the times in `tlist`.
"""
if self.nvars is None and var != None:
raise SystemError("multi-variable call to a scalar basis")
elif self.nvars is None:
# Single variable basis
return [
sum([coeffs[i] * self(i, t) for i in range(self.N)])
for t in tlist]
elif var is None:
# Multi-variable basis with single list of coefficients
values = np.empty((self.nvars, tlist.size))
offset = 0
for j in range(self.nvars):
coef_len = self.var_ncoefs(j)
values[j] = np.array([
sum([coeffs[offset + i] * self(i, t, var=j)
for i in range(coef_len)])
for t in tlist])
offset += coef_len
return values
else:
return np.array([
sum([coeffs[i] * self(i, t, var=var)
for i in range(self.var_ncoefs(var))])
for t in tlist])
def eval_deriv(self, i, k, t, var=None):
"""Evaluate kth derivative of ith basis function at time t.
Parameters
----------
i : int
Basis function offset.
k : int
Derivative order.
t : float
Time at which to evaluating the derivative.
var : int or None, optional
Variable offset.
Returns
-------
float
"""
raise NotImplementedError("Internal error; improper basis functions")