Skip to content

Commit c4bbdbd

Browse files
committed
Update tbcontrol with new discrete conversion functions and extend blocksim with a simple control diagram
1 parent 12a62a8 commit c4bbdbd

3 files changed

Lines changed: 157 additions & 8 deletions

File tree

tbcontrol/blocksim.py

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def change_state(self, x):
131131
def derivative(self, e):
132132
return 0
133133

134-
134+
135135
class Deadtime(Block):
136136
def __init__(self, name, inputname, outputname, delay):
137137
super().__init__(name, inputname, outputname)
@@ -161,30 +161,44 @@ def change_state(self, x):
161161
def derivative(self, e):
162162
return 0
163163

164+
164165
class DiscreteTF(Block):
165166

166167
def __init__(self, name, input_name, output_name, dt, numerator, denominator):
167168
"""
168169
Represents a discrete transfer function.
169-
The TF must be of the form: (b_N * z**(-N) + ... + b_0)/(a_M z**(-M) + ... + a_0 ).
170+
171+
The TF must be of the form:
172+
173+
-1 -2 -n
174+
b + b z + b z + ... + b z
175+
0 1 2 n
176+
-----------------------------------
177+
-1 -2 -m
178+
a + a z + a z + ... + a z
179+
0 1 2 m
180+
170181
171182
Parameters
172183
----------
173184
dt : float
174185
The sampling time of the transfer function.
175186
numerator : array_like
176187
The numerator coefficient vector in a 1-D sequence.
177-
[b_N, ..., b_0]
188+
[b_0, ..., b_n]
178189
denominator : array_like
179190
The denominator coefficient vector in a 1-D sequence.
180-
[a_N, ..., a_0]; a_0 != 0
191+
[a_0, ..., a_m]; a_0 != 0
181192
182193
"""
183194
super().__init__(name, input_name, output_name)
184195

196+
if denominator[0] == 0:
197+
raise ValueError('The leading coefficient of the denominator cannot be zero')
198+
185199
self.dt = dt
186-
self.y_cos = denominator
187-
self.u_cos = numerator
200+
self.y_cos = denominator[::-1]
201+
self.u_cos = numerator[::-1]
188202

189203
self.ys = numpy.zeros(len(self.y_cos))
190204
self.us = numpy.zeros(len(self.u_cos))
@@ -232,6 +246,15 @@ def __init__(self, blocks, sums, inputs):
232246
:param blocks: list of blocks
233247
:param sums: sums specified as dictionaries with keys equal to output signal and values as tuples of strings of the form "<sign><signal>"
234248
:param inputs: inputs specified as dictionaries with keys equal to signal names and values functions of time
249+
250+
251+
Example
252+
253+
>>> blocks = [Gc, G]
254+
>>> sums = {'e': ('+ysp', '-y')}
255+
>>> inputs = {'ysp': step()}
256+
>>> diagram = Diagram(blocks, sums, inputs)
257+
235258
"""
236259
if not all(isinstance(block, Block) for block in blocks):
237260
raise TypeError("blocks must be a list of blocks")
@@ -277,7 +300,7 @@ def simulate(self, ts, progress=False):
277300
"""
278301

279302
if progress:
280-
from tqdm import tqdm_notebook as tqdm
303+
from tqdm.auto import tqdm as tqdm
281304
pbar = tqdm(total=len(ts))
282305
dt = ts[1]
283306
outputs = defaultdict(list)
@@ -296,9 +319,65 @@ def __repr__(self):
296319

297320
# Input functions
298321
def step(initial=0, starttime=0, size=1):
322+
"""Return a function which can be used to simulate a step"""
299323
def stepfunction(t):
300324
if t < starttime:
301325
return initial
302326
else:
303327
return initial + size
304328
return stepfunction
329+
330+
331+
def zero(t):
332+
"""This function returns zero for all time"""
333+
return 0
334+
335+
336+
def simple_control_diagram(Gc, G, Gd=None, Gm=None, ysp=step(), d=zero):
337+
"""Construct a simple control diagram for quick controller simulations
338+
339+
| d
340+
┌─────┐
341+
│ Gd │
342+
└──┬──┘
343+
│ yd
344+
ysp + e ┌──────┐ u ┌─────┐ yu v y
345+
──>o─>│ Gc ├────>│ G ├───>o─┬──>
346+
─↑ └──────┘ └─────┘ │
347+
│ │
348+
│ ym ┌─────┐ │
349+
└─────────┤ Gm │<───────────┘
350+
└─────┘
351+
352+
353+
Required arguments:
354+
355+
Gc: Controller, a blocksim.Block with name='Gc', input='e', output='u'
356+
G: System, a blocksim.Block with name='G', input='u', output='yu'
357+
358+
Optional arguments:
359+
Gd: disturbance response, a blocksim.Block with name='Gd', input='d', output='yd'
360+
ysp: a function of time to represent the input
361+
d: a function of time to represent the disturbance
362+
363+
Returns
364+
365+
blocksim.Diagram object representing this diagram
366+
367+
"""
368+
369+
if Gd is None:
370+
Gd = Zero('Gd', 'd', 'yd')
371+
372+
if Gm is None:
373+
Gm = LTI('Gm', 'y', 'ym', 1)
374+
375+
blocks = [Gc, G, Gd, Gm]
376+
377+
sums = {'e': ('+ysp', '-ym'),
378+
'y': ('+yu', '+yd')}
379+
380+
inputs = {'ysp': ysp,
381+
'd': d}
382+
383+
return Diagram(blocks, sums, inputs)

tbcontrol/conversion.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
def discrete_coeffs_neg_to_pos(numer, denom):
2+
"""Convert the coefficients of a transfer function from negative to positive powers of z
3+
4+
numer and denom must be lists of coefficients of negative powers of z, in descending powers of z
5+
6+
convert from
7+
8+
-1 -2 -n
9+
b + b z + b z + ... + b z numer = [b0, b1, b2, ...]
10+
0 1 2 n
11+
------------------------------
12+
-1 -2 -m
13+
a + a z + a z + ... + a z denom = [a0, b1, b2, ...]
14+
0 1 2 m
15+
16+
to
17+
18+
k k-1 k-2
19+
b z + b z + b z + ...
20+
0 1 2
21+
-------------------------------
22+
k k-1 k-2
23+
a z + a z + a z + ...
24+
0 1 2
25+
26+
"""
27+
28+
n = len(numer)
29+
m = len(denom)
30+
31+
k = max(m, n)
32+
33+
return list(numer) + [0]*(k - n), list(denom) + [0]*(k - m)
34+
35+
36+
def discrete_coeffs_pos_to_neg(numer, denom):
37+
"""Convert the coefficients of a transfer function from positive to negative powers of z
38+
39+
numer and denom must be lists of coefficients of negative powers of z, in descending powers of z
40+
41+
convert from
42+
43+
m m-1 m-2
44+
b z + b z + b z + ... numer = [b0, b1, b2, ...]
45+
0 1 2
46+
-------------------------
47+
n n-1 n-2
48+
a z + a z + a z + ... denom = [a0, b1, b2, ...]
49+
0 1 2
50+
51+
52+
to
53+
54+
-1 -2 -n
55+
b + b z + b z + ... + b z
56+
0 1 2 n
57+
------------------------------
58+
-1 -2 -m
59+
a + a z + a z + ... + a z
60+
0 1 2 m
61+
62+
"""
63+
64+
n = len(numer)
65+
m = len(denom)
66+
67+
k = max(m, n)
68+
69+
return [0]*(k - n) + list(numer), [0]*(k - m) + list(denom)
70+

tbcontrol/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# This file is designed to be `exec`ed, don't do too much here
22

3-
__version__ = "0.1.10"
3+
__version__ = "0.2.1"

0 commit comments

Comments
 (0)