2 * Copyright 2007 by Robert Dodier
3 * I release this work under terms of GNU General Public License
5 * Summary. Z-transforms for various special cases are implemented as
6 * pattern-matching rules. Given an expression like z_transform(foo(n, z), n, z),
7 * for most rules it's necessary to have the variables n and z in hand before
8 * looking at foo(n, z). However, the Maxima pattern matcher does not have
9 * backtracking, so one rule (r0 below) captures n and z, then all other
12 * The inverse transform isn't implemented yet. For some inspiration, see:
13 * http://ece.citadel.edu/barsanti/elec407/L3%20Inverse%20Z%20Transforms.pdf
14 * and: http://www.reduce-algebra.com/docs/ztrans.pdf
17 put ('z_transform, true, 'present);
19 apply_z_transform (e) := apply1 (e, r0);
21 matchdeclare ([nn, zz], symbolp);
22 matchdeclare (aa, all);
25 z_transform (aa, nn, zz),
26 block ([nn% : nn, zz% : zz],
28 (z_transform (aa, nn, zz),
29 r913_1a, r913_1b, r913_2a, r913_2b, r913_3a, r913_3b,
30 r913_4, r913_5, r913_6, r913_7, r913_10, r913_12, r914_4,
31 r914_6, /* r914_9, */ r914_10, r914_11a, r914_11b, r914_12,
32 r914_13, r914_14, r914_15a, r914_16)));
34 /* Some specific transforms.
35 * Table 9.1.3 at: http://mathfaculty.fullerton.edu/MATHEWS/C2003/ZTRANSFORMINTROMOD.HTML
39 * (have to try kron_delta both ways ... sigh)
45 z_transform (kron_delta (nn%, aa), nn%, zz%),
49 z_transform (kron_delta (aa, nn%), nn%, zz%),
54 /* (2) u[n] --> z/(z - 1) */
57 z_transform (1, nn%, zz%),
61 z_transform (unit_step (nn%), nn%, zz%),
64 /* (3) b^n --> z/(z - b) */
66 matchdeclare (bb, freeof (nn%, zz%));
69 z_transform (bb^nn%, nn%, zz%),
73 z_transform (1/(bb^nn%), nn%, zz%),
76 /* (4) b^(n - 1) * u[n - 1] --> 1/(z - b) */
79 z_transform (bb^(nn% - 1) * unit_step (nn% - 1), nn%, zz%),
82 /* (5) e^(a*n) --> z/(z - e^a) */
84 matchdeclare (aa, lambda ([e], e # 0 and freeof (nn%, zz%, e)));
87 z_transform (exp (aa * nn%), nn%, zz%),
88 zz / (zz - exp (aa)));
90 /* (6) n --> z/(z - 1)^2 */
93 z_transform (nn%, nn%, zz%),
96 /* (7) n^2 --> z*(z + 1)/(z - 1)^3 */
99 z_transform (nn%^2, nn%, zz%),
100 zz*(zz + 1) / (zz - 1)^3);
102 /* (8) b^n*n --> b*z/(z - b)^2
103 * via (6) + frequency scaling
106 /* (9) e^(a*n)*n --> z*e^a/(z - e^a)^2
107 * via (6) + complex translation
110 /* (10) sin(a*n) --> sin(a)*z/(z^2 - 2*cos(a)*z + 1) */
113 z_transform (sin (aa*nn%), nn%, zz%),
114 sin(aa)*zz / (zz^2 - 2*cos(aa)*zz + 1));
116 /* (11) b^n*sin(a*n) --> sin(a)*b*z/(z^2 - 2*cos(a)*b*z + b^2)
117 * via (10) + frequency scaling
120 /* (12) cos(a*n) --> z*(z - cos(a))/(z^2 - 2*cos(a)*z + 1) */
123 z_transform (cos (aa*nn%), nn%, zz%),
124 zz*(zz - cos(aa)) / (zz^2 - 2*cos(aa)*zz + 1));
126 /* (13) b^n*cos(a*n) --> z*(z - b*cos(a))/(z^2 - 2*cos(a)*b*z + b^2)
127 * via (11) + frequency scaling
131 /* General properties.
132 * Table 9.1.4 at: http://mathfaculty.fullerton.edu/MATHEWS/C2003/ZTRANSFORMINTROMOD.HTML
135 /* (4) u[n - m] --> z^(1 - m)/(z - 1)
136 * (delayed unit step)
139 matchdeclare (mm, integerp);
142 z_transform (unit_step (nn% - mm), nn%, zz%),
143 zz^(1 - mm) / (zz - 1));
145 /* (5) x[n - 1]*u[n - 1] --> (1/z)*X(z)
149 /* (6) x[n - m]*u[n - m] --> z^(-m)*X(z)
150 * (time delayed shift)
154 z_transform (aa * unit_step (nn% - mm), nn%, zz%),
155 z^(-m) * z_transform (subst (nn + mm, nn, aa), nn, zz));
157 /* (7) x[n + 1] --> z*(X(z) - x[0])
158 * (8) x[n + 2] --> z^2*(X(z) - x[0] - x[1]*z^(-1))
159 * via (9) w/ m = 1 and m = 2 respectively
162 /* (9) x[n + m] --> z^m*(X(z) - sum(x[i]*z^(-i), i, 0, m - 1))
166 /* HMM, NOT SURE HOW TO DO (9) ... FOLLOWING STUFF IS BROKEN */
168 matchdeclare (mm, lambda ([e], integerp(e) and e > 0));
169 defmatch (n_plus_m, nn% + mm);
171 matchdeclare (xxnpm, lambda ([e], n_plus_m (e) # false));
174 z_transform (ss, nn%, zz%),
175 zz^mm * z_transform (subst (nn - mm, nn, ss), nn, zz));
177 /* (10) e^(a*n)*x[n] --> X(z*e^(-a))
178 * (complex translation)
181 matchdeclare (nz, lambda ([e], e # 0 and freeof (nn%, zz%, e)));
184 z_transform (exp (nz * nn%) * bb, nn%, zz%),
185 'subst (zz/exp(nz), zz, z_transform (bb, nn, zz)));
187 /* (11) b^n*x[n] --> X(z/b)
188 * (frequency scaling)
191 matchdeclare (xx, all);
192 matchdeclare (bb, freeof (nn%, zz%));
195 z_transform (bb^nn% * xx, nn%, zz%),
196 'subst (zz/bb, zz, z_transform (xx, nn, zz)));
199 z_transform (1/(bb^nn%) * xx, nn%, zz%),
200 'subst (zz*bb, zz, z_transform (xx, nn, zz)));
202 /* (12) n*x[n] --> -z X'(z)
206 matchdeclare (aa, all);
207 matchdeclare (kk, lambda ([e], integerp(e) and e > 0));
210 z_transform (aa*nn%^kk, nn%, zz%),
211 block ([ee : - zz * 'diff (z_transform (aa, nn, zz), zz)],
212 for i:2 thru kk do ee : - zz * 'diff (ee, zz), ee));
214 /* (13) (1/n)*x[n] --> - \int X(z)/z dz
218 matchdeclare (uu, lambda ([e], not atom(e) and op(e) = "/" and member (nn%, second(e))));
221 z_transform (uu, nn%, zz%),
222 'integrate (zz^-1 * z_transform (aa, nn, zz), zz));
224 /* (14) 1/(n + m)*x[n] --> - z^(-m) * \int X(z)/z^(m + 1) dz
225 * (integration shift)
228 matchdeclare (mm, lambda ([e], integerp(e) and e > 0));
231 z_transform (aa/(nn% + mm), nn%, zz%),
232 - zz^(-mm) * 'integrate (z^-(mm + 1) * z_transform (aa, nn, zz), zz));
234 /* (15) x[n] (star) y[n] = \sum_{i=0}^n x[i]*y[n - i] --> X(z)*Y(z)
235 * (discrete time convolution)
238 matchdeclare (cc, lambda ([e], not atom(e) and op(e) = 'convolution));
241 z_transform (cc, nn%, zz%),
242 block ([a : args(cc)], product (z_transform (a[i], nn, zz), i, 1 , length(a))));
244 /* ANOTHER RULE R914_15B FOR EXPLICIT 'SUM EXPRESSION WOULD BE NICE ... */
246 /* (16) \sum_{i=0}^n x[i] --> z/(z - 1)*X(z)
247 * (convolution with y[n] = 1)
250 matchdeclare (ii, symbolp);
255 z_transform ('sum (aa, ii, 0, nn%), nn%, zz%),
256 zz/(zz - 1) * z_transform (subst (nn, ii, aa), nn, zz));
260 /* ((17) & (18) -- not transform pairs) */
262 /* (put linearity declaration last, otherwise messes up rules) */
265 * (2) constant multiple
269 declare (z_transform, linear);