2 # Copyright (C) 2011 W. Trevor King <wking@drexel.edu>
4 # This file is part of pypid.
6 # pypid is free software: you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation, either
9 # version 3 of the License, or (at your option) any later version.
11 # pypid is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with pypid. If not, see
18 # <http://www.gnu.org/licenses/>.
21 from argparse import ArgumentParser
22 from sys import stdout
23 from time import sleep
26 from matplotlib import pyplot
27 from numpy import loadtxt
28 except (ImportError,RuntimeError), e:
33 from pypid.backend.test import TestBackend
34 from pypid.rules import ziegler_nichols_step_response
37 parser = ArgumentParser(description='Simulate a step response.')
39 '-K', '--process-gain', metavar='GAIN', type=float, default=1,
40 help='process gain (PV-units over MV-units)',)
42 '-L', '--dead-time', metavar='TIME', type=float, default=1,
43 help='system dead time (lag)')
45 '-T', '--decay-time', metavar='TIME', type=float, default=1,
46 help='exponential decay timescale')
48 '-P', '--proportional', metavar='GAIN', type=float, default=None,
49 help='process gain (output units over input units)',)
51 '-I', '--integral', metavar='TIME', type=float, default=None,
52 help='intergral gain timescale')
54 '-D', '--derivative', metavar='TIME', type=float, default=None,
55 help='derivative gain timescale')
57 '-M', '--max-mv', metavar='MV', type=float, default=100.,
58 help='maximum manipulated variable')
60 '-A', '--tuning-algorithm', metavar='TUNER', default=None,
61 choices=['ZN'], help='step tuning algorithm')
63 '-m', '--mode', metavar='MODE', default='PID',
64 choices=['P', 'PI', 'PID'], help='controller mode')
66 '-t', '--time', metavar='TIME', type=float, default=10.,
67 help='simulation time')
69 '-o', '--output', default='-', help='output log file')
71 '-p', '--plot', action='store_true', default=False,
72 help='plot the repsonse')
74 args = parser.parse_args()
76 if args.plot and not (pyplot and loadtxt) :
77 raise plot_import_error
79 if args.output == '-':
82 raise ValueError('can only plot when outputing to a file')
84 log_stream = open(args.output, 'w')
90 p,i,d = (0, float('inf'), 0)
91 if args.tuning_algorithm == 'ZN':
92 p,i,d = ziegler_nichols_step_response(
93 process_gain=K, dead_time=L, decay_time=T, mode=args.mode)
103 process_gain=K, dead_time=L, decay_time=T, max_mv=args.max_mv,
104 log_stream=log_stream)
106 b.set_up_gains(proportional=p, integral=i, derivative=d)
107 b.set_down_gains(proportional=p, integral=i, derivative=d)
112 if args.output != '-':
116 header = open(args.output, 'r').readline()
117 label = header.strip('#\n').split('\t')
118 data = loadtxt(args.output)
119 times = data[:,0] - data[0,0]
122 for i in range(1, len(label)):
125 pyplot.legend(loc='best') # add legend to previous subplot
126 pyplot.subplot(3, 1, subplot)
128 pyplot.plot(times, data[:,i], '.', label=label[i])
129 pyplot.legend(loc='best')