@@ -131,7 +131,7 @@ def change_state(self, x):
131131 def derivative (self , e ):
132132 return 0
133133
134-
134+
135135class 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+
164165class 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
298321def 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 )
0 commit comments