~ubuntu-branches/debian/sid/octave3.0/sid

« back to all changes in this revision

Viewing changes to scripts/polynomial/residue.m

  • Committer: Bazaar Package Importer
  • Author(s): Rafael Laboissiere
  • Date: 2007-12-23 16:04:15 UTC
  • Revision ID: james.westby@ubuntu.com-20071223160415-n4gk468dihy22e9v
Tags: upstream-3.0.0
ImportĀ upstreamĀ versionĀ 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
## Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2004, 2005
 
2
##                2006, 2007 John W. Eaton
 
3
## Copyright (C) 2007 Ben Abbott
 
4
##
 
5
## This file is part of Octave.
 
6
##
 
7
## Octave is free software; you can redistribute it and/or modify it
 
8
## under the terms of the GNU General Public License as published by
 
9
## the Free Software Foundation; either version 3 of the License, or (at
 
10
## your option) any later version.
 
11
##
 
12
## Octave is distributed in the hope that it will be useful, but
 
13
## WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
## General Public License for more details.
 
16
##
 
17
## You should have received a copy of the GNU General Public License
 
18
## along with Octave; see the file COPYING.  If not, see
 
19
## <http://www.gnu.org/licenses/>.
 
20
 
 
21
## -*- texinfo -*-
 
22
## @deftypefn {Function File} {[@var{r}, @var{p}, @var{k}, @var{e}] =} residue (@var{b}, @var{a})
 
23
## Compute the partial fraction expansion for the quotient of the
 
24
## polynomials, @var{b} and @var{a}.
 
25
##
 
26
## @iftex
 
27
## @tex
 
28
## $$
 
29
## {B(s)\over A(s)} = \sum_{m=1}^M {r_m\over (s-p_m)^e_m}
 
30
##   + \sum_{i=1}^N k_i s^{N-i}.
 
31
## $$
 
32
## @end tex
 
33
## @end iftex
 
34
## @ifinfo
 
35
##
 
36
## @example
 
37
##  B(s)    M       r(m)         N
 
38
##  ---- = SUM -------------  + SUM k(i)*s^(N-i)
 
39
##  A(s)   m=1 (s-p(m))^e(m)    i=1
 
40
## @end example
 
41
## @end ifinfo
 
42
##
 
43
## @noindent
 
44
## where @math{M} is the number of poles (the length of the @var{r},
 
45
## @var{p}, and @var{e}), the @var{k} vector is a polynomial of order @math{N-1}
 
46
## representing the direct contribution, and the @var{e} vector specifies
 
47
## the multiplicity of the mth residue's pole.
 
48
##
 
49
## For example,
 
50
##
 
51
## @example
 
52
## @group
 
53
## b = [1, 1, 1];
 
54
## a = [1, -5, 8, -4];
 
55
## [r, p, k, e] = residue (b, a);
 
56
##      @result{} r = [-2; 7; 3]
 
57
##      @result{} p = [2; 2; 1]
 
58
##      @result{} k = [](0x0)
 
59
##      @result{} e = [1; 2; 1]
 
60
## @end group
 
61
## @end example
 
62
##
 
63
## @noindent
 
64
## which represents the following partial fraction expansion
 
65
## @iftex
 
66
## @tex
 
67
## $$
 
68
## {s^2+s+1\over s^3-5s^2+8s-4} = {-2\over s-2} + {7\over (s-2)^2} + {3\over s-1}
 
69
## $$
 
70
## @end tex
 
71
## @end iftex
 
72
## @ifinfo
 
73
##
 
74
## @example
 
75
##         s^2 + s + 1       -2        7        3
 
76
##    ------------------- = ----- + ------- + -----
 
77
##    s^3 - 5s^2 + 8s - 4   (s-2)   (s-2)^2   (s-1)
 
78
## @end example
 
79
##
 
80
## @end ifinfo
 
81
##
 
82
## @deftypefnx {Function File} {[@var{b}, @var{a}] =} residue (@var{r}, @var{p}, @var{k})
 
83
## @deftypefnx {Function File} {[@var{b}, @var{a}] =} residue (@var{r}, @var{p}, @var{k}, @var{e})
 
84
## Compute the reconstituted quotient of polynomials,
 
85
## @var{b}(s)/@var{a}(s), from the partial fraction expansion
 
86
## represented by the residues, poles, and a direct polynomial specified
 
87
## by @var{r}, @var{p} and @var{k}, and the pole multiplicity @var{e}.
 
88
##
 
89
## If the multiplicity, @var{e}, is not explicitly specified the multiplicity is
 
90
## determined by the script mpoles.m.
 
91
##
 
92
## For example,
 
93
##
 
94
## @example
 
95
## @group
 
96
## r = [-2; 7; 3];
 
97
## p = [2; 2; 1];
 
98
## k = [1, 0];
 
99
## [b, a] = residue (r, p, k);
 
100
##      @result{} b = [1, -5, 9, -3, 1]
 
101
##      @result{} a = [1, -5, 8, -4]
 
102
##
 
103
## where mpoles.m is used to determine e = [1; 2; 1]
 
104
##
 
105
## @end group
 
106
## @end example
 
107
##
 
108
## Alternatively the multiplicity may be defined explicitly, for example,
 
109
##
 
110
## @example
 
111
## @group
 
112
## r = [7; 3; -2];
 
113
## p = [2; 1; 2];
 
114
## k = [1, 0];
 
115
## e = [2; 1; 1];
 
116
## [b, a] = residue (r, p, k, e);
 
117
##      @result{} b = [1, -5, 9, -3, 1]
 
118
##      @result{} a = [1, -5, 8, -4]
 
119
## @end group
 
120
## @end example
 
121
##
 
122
## @noindent
 
123
## which represents the following partial fraction expansion
 
124
## @iftex
 
125
## @tex
 
126
## $$
 
127
## {-2\over s-2} + {7\over (s-2)^2} + {3\over s-1} + s = {s^4-5s^3+9s^2-3s+1\over s^3-5s^2+8s-4}
 
128
## $$
 
129
## @end tex
 
130
## @end iftex
 
131
## @ifinfo
 
132
##
 
133
## @example
 
134
##     -2        7        3         s^4 - 5s^3 + 9s^2 - 3s + 1
 
135
##    ----- + ------- + ----- + s = --------------------------
 
136
##    (s-2)   (s-2)^2   (s-1)          s^3 - 5s^2 + 8s - 4
 
137
## @end example
 
138
## @end ifinfo
 
139
## @seealso{poly, roots, conv, deconv, mpoles, polyval, polyderiv, polyinteg}
 
140
## @end deftypefn
 
141
 
 
142
## Author: Tony Richardson <arichard@stark.cc.oh.us>
 
143
## Author: Ben Abbott <bpabbott@mac.com>
 
144
## Created: June 1994
 
145
## Adapted-By: jwe
 
146
 
 
147
function [r, p, k, e] = residue (b, a, varargin)
 
148
 
 
149
  if (nargin < 2 || nargin > 4)
 
150
    print_usage ();
 
151
  endif
 
152
 
 
153
  toler = .001;
 
154
 
 
155
  if (nargin >= 3)
 
156
    if (nargin >= 4)
 
157
      e = varargin{2};
 
158
    else
 
159
      e = [];
 
160
    endif
 
161
    ## The inputs are the residue, pole, and direct part. Solve for the
 
162
    ## corresponding numerator and denominator polynomials
 
163
    [r, p] = rresidue (b, a, varargin{1}, toler, e);
 
164
    return
 
165
  endif
 
166
 
 
167
  ## Make sure both polynomials are in reduced form.
 
168
 
 
169
  a = polyreduce (a);
 
170
  b = polyreduce (b);
 
171
 
 
172
  b = b / a(1);
 
173
  a = a / a(1);
 
174
 
 
175
  la = length (a);
 
176
  lb = length (b);
 
177
 
 
178
  ## Handle special cases here.
 
179
 
 
180
  if (la == 0 || lb == 0)
 
181
    k = r = p = e = [];
 
182
    return;
 
183
  elseif (la == 1)
 
184
    k = b / a;
 
185
    r = p = e = [];
 
186
    return;
 
187
  endif
 
188
 
 
189
  ## Find the poles.
 
190
 
 
191
  p = roots (a);
 
192
  lp = length (p);
 
193
 
 
194
  ## Determine if the poles are (effectively) zero.
 
195
 
 
196
  small = max (abs (p));
 
197
  small = max ([small, 1] ) * 1e-8 * (1 + numel (p))^2;
 
198
  p(abs (p) < small) = 0;
 
199
 
 
200
  ## Determine if the poles are (effectively) real, or imaginary.
 
201
 
 
202
  index = (abs (imag (p)) < small);
 
203
  p(index) = real (p(index));
 
204
  index = (abs (real (p)) < small);
 
205
  p(index) = 1i * imag (p(index));
 
206
 
 
207
  ## Sort poles so that multiplicity loop will work.
 
208
 
 
209
  [e, indx] = mpoles (p, toler, 1);
 
210
  p = p (indx);
 
211
 
 
212
  ## Find the direct term if there is one.
 
213
 
 
214
  if (lb >= la)
 
215
    ## Also return the reduced numerator.
 
216
    [k, b] = deconv (b, a);
 
217
    lb = length (b);
 
218
  else
 
219
    k = [];
 
220
  endif
 
221
 
 
222
  if (lp == 1)
 
223
    r = polyval (b, p);
 
224
    return;
 
225
  endif
 
226
 
 
227
  ## Determine the order of the denominator and remaining numerator.
 
228
  ## With the direct term removed the potential order of the numerator
 
229
  ## is one less than the order of the denominator.
 
230
 
 
231
  aorder = numel (a) - 1;
 
232
  border = aorder - 1;
 
233
 
 
234
  ## Construct a system of equations relating the individual
 
235
  ## contributions from each residue to the complete numerator.
 
236
 
 
237
  A = zeros (border+1, border+1);
 
238
  B = prepad (reshape (b, [numel(b), 1]), border+1, 0);
 
239
  for ip = 1:numel(p)
 
240
    ri = zeros (size (p));
 
241
    ri(ip) = 1;
 
242
    A(:,ip) = prepad (rresidue (ri, p, [], toler), border+1, 0).';
 
243
  endfor
 
244
 
 
245
  ## Solve for the residues.
 
246
 
 
247
  r = A \ B;
 
248
 
 
249
endfunction
 
250
 
 
251
function [pnum, pden, e] = rresidue (r, p, k, toler, e)
 
252
 
 
253
  ## Reconstitute the numerator and denominator polynomials from the
 
254
  ## residues, poles, and direct term.
 
255
 
 
256
  if (nargin < 2 || nargin > 5)
 
257
    print_usage ();
 
258
  endif
 
259
 
 
260
  if (nargin < 5)
 
261
    e = [];
 
262
  endif
 
263
 
 
264
  if (nargin < 4)
 
265
    toler = [];
 
266
  endif
 
267
 
 
268
  if (nargin < 3)
 
269
    k = [];
 
270
  endif
 
271
 
 
272
  if numel (e)
 
273
    indx = 1:numel(p);
 
274
  else
 
275
    [e, indx] = mpoles (p, toler, 0);
 
276
    p = p (indx);
 
277
    r = r (indx);
 
278
  endif
 
279
 
 
280
  indx = 1:numel(p);
 
281
 
 
282
  for n = indx
 
283
    pn = [1, -p(n)];
 
284
    if n == 1
 
285
      pden = pn;
 
286
    else
 
287
      pden = conv (pden, pn);
 
288
    endif
 
289
  endfor
 
290
 
 
291
  ## D is the order of the denominator
 
292
  ## K is the order of the direct polynomial
 
293
  ## N is the order of the resulting numerator
 
294
  ## pnum(1:(N+1)) is the numerator's polynomial
 
295
  ## pden(1:(D+1)) is the denominator's polynomial
 
296
  ## pm is the multible pole for the nth residue
 
297
  ## pn is the numerator contribution for the nth residue
 
298
 
 
299
  D = numel (pden) - 1;
 
300
  K = numel (k) - 1;
 
301
  N = K + D;
 
302
  pnum = zeros (1, N+1);
 
303
  for n = indx(abs (r) > 0)
 
304
    p1 = [1, -p(n)];
 
305
    for m = 1:e(n)
 
306
      if (m == 1)
 
307
        pm = p1;
 
308
      else
 
309
        pm = conv (pm, p1);
 
310
      endif
 
311
    endfor
 
312
    pn = deconv (pden, pm);
 
313
    pn = r(n) * pn;
 
314
    pnum = pnum + prepad (pn, N+1, 0, 2);
 
315
  endfor
 
316
 
 
317
  ## Add the direct term.
 
318
 
 
319
  if (numel (k))
 
320
    pnum = pnum + conv (pden, k);
 
321
  endif
 
322
 
 
323
  ## Check for leading zeros and trim the polynomial coefficients.
 
324
 
 
325
  small = max ([max(abs(pden)), max(abs(pnum)), 1]) * eps;
 
326
 
 
327
  pnum(abs (pnum) < small) = 0;
 
328
  pden(abs (pden) < small) = 0;
 
329
 
 
330
  pnum = polyreduce (pnum);
 
331
  pden = polyreduce (pden);
 
332
 
 
333
endfunction
 
334
 
 
335
%!test
 
336
%! b = [1, 1, 1];
 
337
%! a = [1, -5, 8, -4];
 
338
%! [r, p, k, e] = residue (b, a);
 
339
%! assert (abs (r - [-2; 7; 3]) < 1e-5
 
340
%!   && abs (p - [2; 2; 1]) < 1e-7
 
341
%!   && isempty (k)
 
342
%!   && e == [1; 2; 1]);
 
343
%! k = [1 0];
 
344
%! b = conv (k, a) + prepad (b, numel (k) + numel (a) - 1, 0);
 
345
%! a = a;
 
346
%! [br, ar] = residue (r, p, k);
 
347
%! assert ((abs (br - b) < 1e-12
 
348
%!   && abs (ar - a) < 1e-12));
 
349
%! [br, ar] = residue (r, p, k, e);
 
350
%! assert ((abs (br - b) < 1e-12
 
351
%!   && abs (ar - a) < 1e-12));
 
352
 
 
353
%!test
 
354
%! b = [1, 0, 1];
 
355
%! a = [1, 0, 18, 0, 81];
 
356
%! [r, p, k, e] = residue(b, a);
 
357
%! r1 = [-5i; 12; +5i; 12]/54;
 
358
%! p1 = [+3i; +3i; -3i; -3i];
 
359
%! assert (abs (r - r1) < 1e-7 && abs (p - p1) < 1e-7
 
360
%!   && isempty (k)
 
361
%!   && e == [1; 2; 1; 2]);
 
362
%! [br, ar] = residue (r, p, k);
 
363
%! assert ((abs (br - b) < 1e-12
 
364
%!   && abs (ar - a) < 1e-12));
 
365
 
 
366
%!test
 
367
%! r = [7; 3; -2];
 
368
%! p = [2; 1; 2];
 
369
%! k = [1 0];
 
370
%! e = [2; 1; 1];
 
371
%! [b, a] = residue (r, p, k, e);
 
372
%! assert ((abs (b - [1, -5, 9, -3, 1]) < 1e-12
 
373
%!   && abs (a - [1, -5, 8, -4]) < 1e-12));
 
374
%! [rr, pr, kr, er] = residue (b, a);
 
375
%! [jnk, n] = mpoles(p);
 
376
%! assert ((abs (rr - r(n)) < 1e-5
 
377
%!   && abs (pr - p(n)) < 1e-7
 
378
%!   && abs (kr - k) < 1e-12
 
379
%!   && abs (er - e(n)) < 1e-12));
 
380
 
 
381
%!test
 
382
%! b = [1];
 
383
%! a = [1, 10, 25];
 
384
%! [r, p, k, e] = residue(b, a);
 
385
%! r1 = [0; 1];
 
386
%! p1 = [-5; -5];
 
387
%! assert (abs (r - r1) < 1e-7 && abs (p - p1) < 1e-7
 
388
%!   && isempty (k)
 
389
%!   && e == [1; 2]);
 
390
%! [br, ar] = residue (r, p, k);
 
391
%! assert ((abs (br - b) < 1e-12
 
392
%!   && abs (ar - a) < 1e-12));