File: __time_response__.m

package info (click to toggle)
octave-control 2.3.52-1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 4,680 kB
  • sloc: cpp: 5,104; objc: 91; makefile: 52
file content (304 lines) | stat: -rw-r--r-- 7,747 bytes parent folder | download
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
## Copyright (C) 2009, 2010   Lukas F. Reichlin
##
## This file is part of LTI Syncope.
##
## LTI Syncope 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.
##
## LTI Syncope 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 LTI Syncope.  If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## Common code for the time response functions step, impulse and initial.

## Author: Lukas Reichlin <lukas.reichlin@gmail.com>
## Created: October 2009
## Version: 0.2

function [y, t, x_arr] = __time_response__ (sys, resptype, plotflag, tfinal, dt, x0, sysname)

  if (! isa (sys, "ss"))
    sys = ss (sys);                                    # sys must be proper
  endif

  if (is_real_vector (tfinal) && length (tfinal) > 1)  # time vector t passed
    dt = tfinal(2) - tfinal(1);                        # assume that t is regularly spaced
    tfinal = tfinal(end);
  endif

  [A, B, C, D, tsam] = ssdata (sys);

  discrete = ! isct (sys);                             # static gains are treated as analog systems
  tsam = abs (tsam);                                   # use 1 second if tsam is unspecified (-1)

  if (discrete)
    if (! isempty (dt))
      warning ("time_response: argument dt has no effect on sampling time of discrete system");
    endif

    dt = tsam;
  endif

  [tfinal, dt] = __sim_horizon__ (A, discrete, tfinal, dt);

  if (! discrete)
    sys = c2d (sys, dt, "zoh");
  endif

  [F, G] = ssdata (sys);                               # matrices C and D don't change

  n = rows (F);                                        # number of states
  m = columns (G);                                     # number of inputs
  p = rows (C);                                        # number of outputs

  ## time vector
  t = reshape (0 : dt : tfinal, [], 1);
  l_t = length (t);

  switch (resptype)
    case "initial"
      str = ["Response of ", sysname, " to Initial Conditions"];
      yfinal = zeros (p, 1);

      ## preallocate memory
      y = zeros (l_t, p);
      x_arr = zeros (l_t, n);

      ## initial conditions
      x = reshape (x0, [], 1);                         # make sure that x is a column vector

      if (n != length (x0) || ! is_real_vector (x0))
        error ("initial: x0 must be a real vector with %d elements", n);
      endif

      ## simulation
      for k = 1 : l_t
        y(k, :) = C * x;
        x_arr(k, :) = x;
        x = F * x;
      endfor

    case "step"
      str = ["Step Response of ", sysname];
      yfinal = dcgain (sys);

      ## preallocate memory
      y = zeros (l_t, p, m);
      x_arr = zeros (l_t, n, m);

      for j = 1 : m                                    # for every input channel
        ## initial conditions
        x = zeros (n, 1);
        u = zeros (m, 1);
        u(j) = 1;

        ## simulation
        for k = 1 : l_t
          y(k, :, j) = C * x + D * u;
          x_arr(k, :, j) = x;
          x = F * x + G * u;
        endfor
      endfor

    case "impulse"
      str = ["Impulse Response of ", sysname];
      yfinal = zeros (p, m);

      ## preallocate memory
      y = zeros (l_t, p, m);
      x_arr = zeros (l_t, n, m);

      for j = 1 : m                                    # for every input channel
        ## initial conditions
        u = zeros (m, 1);
        u(j) = 1;

        if (discrete)
          x = zeros (n, 1);                            # zero by definition 
          y(1, :, j) = D * u / dt;
          x_arr(1, :, j) = x;
          x = G * u / dt;
        else
          x = B * u;                                   # B, not G!
          y(1, :, j) = C * x;
          x_arr(1, :, j) = x;
          x = F * x;
        endif

        ## simulation
        for k = 2 : l_t
          y (k, :, j) = C * x;
          x_arr(k, :, j) = x;
          x = F * x;
        endfor
      endfor

      if (discrete)
        y *= dt;
        x_arr *= dt;
      endif

    otherwise
      error ("time_response: invalid response type");

  endswitch

  
  if (plotflag)                                        # display plot

    ## TODO: Set correct titles, especially for multi-input systems

    stable = isstable (sys);
    outname = get (sys, "outname");
    outname = __labels__ (outname, "y_");

    if (strcmp (resptype, "initial"))
      cols = 1;
    else
      cols = m;
    endif

    if (discrete)                                      # discrete system
      for k = 1 : p
        for j = 1 : cols

          subplot (p, cols, (k-1)*cols+j);

          if (stable)
            stairs (t, [y(:, k, j), yfinal(k, j) * ones(l_t, 1)]);
          else
            stairs (t, y(:, k, j));
          endif

          grid ("on");

          if (k == 1 && j == 1)
            title (str);
          endif

          if (j == 1)
            ylabel (sprintf ("Amplitude %s", outname{k}));
          endif

        endfor
      endfor

      xlabel ("Time [s]");

    else                                               # continuous system
      for k = 1 : p
        for j = 1 : cols

          subplot (p, cols, (k-1)*cols+j);

          if (stable)
            plot (t, [y(:, k, j), yfinal(k, j) * ones(l_t, 1)]);
          else
            plot (t, y(:, k, j));
          endif

          grid ("on");

          if (k == 1 && j == 1)
            title (str);
          endif

          if (j == 1)
            ylabel (sprintf ("Amplitude %s", outname{k}));
          endif

        endfor
      endfor

      xlabel ("Time [s]");

    endif 
  endif

endfunction


function [tfinal, dt] = __sim_horizon__ (A, discrete, tfinal, Ts)

  ## code based on __stepimp__.m of Kai P. Mueller and A. Scottedward Hodel

  TOL = 1.0e-10;                                       # values below TOL are assumed to be zero
  N_MIN = 50;                                          # min number of points
  N_MAX = 2000;                                        # max number of points
  N_DEF = 1000;                                        # default number of points
  T_DEF = 10;                                          # default simulation time

  n = rows (A);
  eigw = eig (A);

  if (discrete)
    ## perform bilinear transformation on poles in z
    for k = 1 : n
      pol = eigw(k);
      if (abs (pol + 1) < TOL)
        eigw(k) = 0;
      else
        eigw(k) = 2 / Ts * (pol - 1) / (pol + 1);
      endif
    endfor
  endif

  ## remove poles near zero from eigenvalue array eigw
  nk = n;
  for k = 1 : n
    if (abs (real (eigw(k))) < TOL)
      eigw(k) = 0;
      nk -= 1;
    endif
  endfor

  if (nk == 0)
    if (isempty (tfinal))
      tfinal = T_DEF;
    endif

    if (! discrete)
      dt = tfinal / N_DEF;
    endif
  else
    eigw = eigw(find (eigw));
    eigw_max = max (abs (eigw));

    if (! discrete)
      dt = 0.2 * pi / eigw_max;
    endif

    if (isempty (tfinal))
      eigw_min = min (abs (real (eigw)));
      tfinal = 5.0 / eigw_min;

      ## round up
      yy = 10^(ceil (log10 (tfinal)) - 1);
      tfinal = yy * ceil (tfinal / yy);
    endif

    if (! discrete)
      N = tfinal / dt;

      if (N < N_MIN)
        dt = tfinal / N_MIN;
      endif

      if (N > N_MAX)
        dt = tfinal / N_MAX;
      endif
    endif
  endif

  if (! isempty (Ts))                                  # catch case cont. system with dt specified
    dt = Ts;
  endif

endfunction