- model: saveAPI.book pk: 83 fields: book_name: Modern Power System Analysis author_name: D. P. Kothari And I. J. Nagrath category: 15 - model: saveAPI.book pk: 154 fields: book_name: Electric Circuits author_name: M. Navhi And J. A. Edminister category: 8 - model: saveAPI.book pk: 181 fields: book_name: Basic Electronics author_name: D. De category: 10 - model: saveAPI.book pk: 215 fields: book_name: Engineering Circuit Analysis author_name: W. Hayt, J. Kemmerly And S. Durbin category: 8 - model: saveAPI.book pk: 293 fields: book_name: Electrical Engineering Fundamentals author_name: V. Del Toro category: 8 - model: saveAPI.book pk: 2048 fields: book_name: Digital Control author_name: K. M. Moudgalya category: 2 - model: saveAPI.book pk: 2777 fields: book_name: Electrical Machines author_name: R. K. Srivastava category: 8 - model: saveAPI.book pk: 3432 fields: book_name: Feedback Control of Dynamic Systems author_name: G. F. Franklin, J. D. Powell and A. Emami-Naeini category: 2 - model: saveAPI.book pk: 3885 fields: book_name: Control Systems author_name: A Nagoor Kani category: 2 - model: saveAPI.bookcategory pk: 2 fields: category_name: Control Theory & Control Systems - model: saveAPI.bookcategory pk: 8 fields: category_name: Electrical Technology - model: saveAPI.bookcategory pk: 10 fields: category_name: Analog Electronics - model: saveAPI.bookcategory pk: 15 fields: category_name: Power Systems - model: saveAPI.gallery pk: 1 fields: save_id: gallery0 name: ch5_1 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 5) Analysis Methods, 5.1) The branch current method' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: clock_c;cmscope;constantvoltage;cscope;currentsensor;ground;resistor;split_f media: gallery0.png script_dump: '' - model: saveAPI.gallery pk: 2 fields: save_id: gallery1 name: ch5_6 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 5) Analysis Methods, 5.6) Network reduction' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: clock_c;cmscope;constantvoltage;cscope;currentsensor;gainblk_f;ground;powblk_f;resistor;split_f;voltagesensor media: gallery1.png script_dump: '' - model: saveAPI.gallery pk: 3 fields: save_id: gallery2 name: ch5_7 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 5) Analysis Methods, 5.7) Superposition' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: bigsom_f;ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;ground;resistor;split_f media: gallery2.png script_dump: '' - model: saveAPI.gallery pk: 4 fields: save_id: gallery3 name: ch6_11 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 6) Amplifiers and Operational Amplifiers, 6.11) Noninverting circuit' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: clock_c;constantvoltage;cscope;ground;matdiv;opamp;potentialsensor;resistor;split_f media: gallery3.png script_dump: '' - model: saveAPI.gallery pk: 5 fields: save_id: gallery4 name: ch6_15 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 6) Amplifiers and Operational Amplifiers, 6.15) Circuits containing several Op amps' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: clock_c;constantvoltage;cscope;ground;opamp;potentialsensor;resistor;split_f media: gallery4.png script_dump: '' - model: saveAPI.gallery pk: 6 fields: save_id: gallery5 name: ch6_9 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 6) Amplifiers and Operational Amplifiers, 6.9) Analysis of circuits containing ideal op amps' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: bigsom_f;clock_c;cmscope;constantvoltage;cscope;currentsensor;gainblk_f;ground;opamp;potentialsensor;powblk_f;resistor;split_f;summation;voltagesensor media: gallery5.png script_dump: '' - model: saveAPI.gallery pk: 7 fields: save_id: gallery6 name: ch8_2 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.2) Capacitor Discharge in a Resistor' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;ground;resistor;split_f media: gallery6.png script_dump: '' - model: saveAPI.gallery pk: 8 fields: save_id: gallery7 name: ch8_3 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.3) Establishing a DC Voltage across a Capacitor' save_time: 2025-05-08 12:24:25+00:00 book: 154 data_dump: blocks: capacitor;clock_c;cmscope;constantvoltage;currentsensor;ground;resistor;split_f;voltagesensor media: gallery7.png script_dump: '' - model: saveAPI.gallery pk: 9 fields: save_id: gallery8 name: ch8_4 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.4) The Source free RL Circuit' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: clock_c;cscope;deriv;gainblk_f;integral_m;split_f;step_function;summation media: gallery8.png script_dump: '' - model: saveAPI.gallery pk: 10 fields: save_id: gallery9 name: ch8_5 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.5) Complex first order RL and RC Circuits' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;inductor;potentialsensor;resistor;split_f media: gallery9.png script_dump: '' - model: saveAPI.gallery pk: 11 fields: save_id: gallery10 name: ch8_6 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.6) Complex first order RL and RC Circuits' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: clock_c;cmscope;cscope;currentsensor;ground;resistor;split_f;voltagesensor media: gallery10.png script_dump: '' - model: saveAPI.gallery pk: 12 fields: save_id: gallery11 name: ch8_7 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.7) DC Steady state in Inductors and Capacitors' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: ccs;clock_c;cmscope;constantvoltage;const_m;cscope;currentsensor;ground;resistor;split_f;voltagesensor media: gallery11.png script_dump: '' - model: saveAPI.gallery pk: 13 fields: save_id: gallery12 name: ch8_8 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.8) DC Steady state in Inductors and Capacitors' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: capacitor;clock_c;cmscope;constantvoltage;deriv;gainblk_f;ground;resistor;split_f;voltagesensor media: gallery12.png script_dump: '' - model: saveAPI.gallery pk: 14 fields: save_id: gallery13 name: ch8_9 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 8) First order Circuits, 8.9) Transitions at Switching Time' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: clock_c;cmscope;constantvoltage;cscope;currentsensor;deriv;gainblk;ground;impsplit_f;integral_m;resistor;split_f;step_function;summation media: gallery13.png script_dump: '' - model: saveAPI.gallery pk: 15 fields: save_id: gallery14 name: ch9_1 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 9) Higher order circuits and Complex frequency, 9.1) Series RLC Circuit' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;ground;inductor;resistor;split_f media: gallery14.png script_dump: '' - model: saveAPI.gallery pk: 16 fields: save_id: gallery15 name: ch9_2 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 9) Higher order circuits and Complex frequency, 9.2) Series RLC Circuit' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;ground;inductor;resistor;split_f media: gallery15.png script_dump: '' - model: saveAPI.gallery pk: 17 fields: save_id: gallery16 name: ch9_5 description: 'Electric Circuits (Author: M. Navhi And J. A. Edminister), 9) Higher order circuits and Complex frequency, 9.5) Parallel RLC circuit' save_time: 2025-05-08 12:24:26+00:00 book: 154 data_dump: blocks: capacitor;clock_c;cscope;ground;inductor;resistor;split_f;voltagesensor media: gallery16.png script_dump: '' - model: saveAPI.gallery pk: 18 fields: save_id: gallery17 name: example3_27 description: 'Basic Electronics (Author: D. De), 3) Diode Circuits, 3.27) Find currents and voltages' save_time: 2025-05-08 12:24:26+00:00 book: 181 data_dump: blocks: clock_c;constantvoltage;cscope;diode;ground;resistor;split_f;text_f;voltagesensor media: gallery17.png script_dump: '// Find currents and voltages // Basic Electronics // By Debashis De // First Edition, 2010 // Dorling Kindersley Pvt. Ltd. India // Example 3-27 in page 179 // Given data //Diode acts as short circuited.Both diodes are forward biased V1=0; // Voltage at junction 1 in V V2=0; // Voltage at junction 2 in V //Calculation I1=(20-V1)/(20*10^3); I2=(V2-(-10))/(20*10^3); printf("I1 = %0.0e A\n",I1); printf("I2 = %0.1e A",I2); // Result // I1 = 1 mA // I2 = 0.5 mA' - model: saveAPI.gallery pk: 19 fields: save_id: gallery18 name: example3_28 description: 'Basic Electronics (Author: D. De), 3) Diode Circuits, 3.28) Find voltage across diode' save_time: 2025-05-08 12:24:26+00:00 book: 181 data_dump: blocks: clock_c;constantvoltage;cscope;diode;ground;resistor;split_f;text_f;voltagesensor media: gallery18.png script_dump: '// Find voltage across diode // Basic Electronics // By Debashis De // First Edition, 2010 // Dorling Kindersley Pvt. Ltd. India // Example 3-28 in page 180 // Given data I=0.1075; // Cirremt across diode in A Rd=1; // Internal resistance of diode in ohm // Calculation Vd=I*Rd; printf("Voltage across diode = %0.4f V",Vd); // Result // Voltage across diode = 0.1075 V' - model: saveAPI.gallery pk: 20 fields: save_id: gallery19 name: example3_30 description: 'Basic Electronics (Author: D. De), 3) Diode Circuits, 3.30) Calculate R Il max' save_time: 2025-05-08 12:24:26+00:00 book: 181 data_dump: blocks: clock_c;cscope;diode;ground;impsplit_f;resistor;split_f;text_f;voltagesensor;vsourceac media: gallery19.png script_dump: '// Calculate R,I_l(max) // Basic Electronics // By Debashis De // First Edition, 2010 // Dorling Kindersley Pvt. Ltd. India // Example 3-30 in page 181 // Given data V_0=50; // Zener diode voltage in V I_L=0; // Load current in A // Calculation R=(150)/(40*10^-3); printf("(a)R = %0.2e ohm\n",R); printf("I_L = I_max when Id = Id_min = 10mA\n"); I_Lmax=40-10; printf("(b)Maximum load current = %0.0f mA",I_Lmax); // Result // (a) R = 3.75 K-ohms // (b) I_Lmax = 30 mA' - model: saveAPI.gallery pk: 21 fields: save_id: gallery20 name: example3_8 description: 'Basic Electronics (Author: D. De), 3) Diode Circuits, 3.8) Calculate the dc load current' save_time: 2025-05-08 12:24:26+00:00 book: 181 data_dump: blocks: clock_c;cscope;diode;ground;impsplit_f;resistor;split_f;text_f;voltagesensor;vsourceac media: gallery20.png script_dump: '// Calculate the dc load current // Basic Electronics // By Debashis De // First Edition, 2010 // Dorling Kindersley Pvt. Ltd. India // Example 3-8 in page 157 // Given data Vm=280; // Supply voltage in V Rl=2000; // Load resistance in ohms Rf=500; // Internal resistance of the diodes in ohms // Calculation Idc=(2*Vm)/(%pi*2500); Idc_t=Idc/2; printf("(a)I_dc = %0.2e A\n(b)I_dc(tube) = %0.2e A\n",Idc,Idc_t); printf("(c)Voltage across conducting diode is sinusoidal with a peak value 0.2 Vm\n"); V_rms=0.905*(280*sqrt(2)); Pdc=Idc^2*Rl; R=(Rf/Rl)*100; printf("Rms voltage V_rms = %0.0f V\n",V_rms); printf("(d)DC output power = %0.1f W\n",Pdc); printf("(e)Percentage regulation = %0.0f percent",R); // Result // (a) Idc = 71 mA, // (b) Idc_tube = 35.7 mA, // (c) V_rms = 358 V, // (d) P_dc = 10.167W, // (e) Percentage regulation = 25%' - model: saveAPI.gallery pk: 22 fields: save_id: gallery21 name: Ex10_1 description: 'Digital Control (Author: K. M. Moudgalya), 10) Special Cases of Pole Placement Control, 10.1) Effect of delay in control performance' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;text_f;tows_c media: gallery21.png script_dump: '// Effect of delay in control performance // 10.1 // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction Ts = 1; B = 0.63; A = [1 -0.37]; k = 5; if k<=0, k = 1; end [zk,dzk] = zpowk(k); // Desired transfer function phi = [1 -0.5]; delta = 1; // internal model of step introduced // Controller design [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,delta); // simulation parameters for stb_disc.xcos // y1: 0 to 1; u1: 0 to 1.2 st = 1.0; // desired change in setpoint t_init = 0; // simulation start time t_final = 20; // simulation end time // simulation parameters for stb_disc.xcos N_var = 0; C = 0; D = 1; N = 1; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 23 fields: save_id: gallery22 name: Ex10_2 description: 'Digital Control (Author: K. M. Moudgalya), 10) Special Cases of Pole Placement Control, 10.2) Smith predictor for paper machine control' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;rand_m;split_f;step_function;super_f;text_f;tows_c media: gallery22.png script_dump: '// Smith predictor for paper machine control in Example 10.2 on page 385. // 10.2 // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction function [C,degC] = poladd(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= cB | rA ~= rB error(''poladd: Inconsistent dimensions''); end degC = max(degA,degB); if degC >= degA A = [A zeros(rA,(degC-degA)*cA)]; end if degC >= degB B = [B zeros(rB,(degC-degB)*cB)]; end C = A+B; endfunction; // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction Ts = 1; B = 0.63; A = [1 -0.37]; k = 3; Bd = convol(B,[0 1]); kd = k - 1; [zkd,dzkd] = zpowk(kd); [mzkd,dmzkd] = poladd(1,0,-zkd,dzkd); // Desired transfer function phi = [1 -0.5]; delta = 1; // Controller design [Rc,Sc,Tc,gamm] = pp_im(B,A,1,phi,delta); // simulation parameters for smith_disc.xcos st = 1.0; // desired change in setpoint t_init = 0; // simulation start time t_final = 20; // simulation end time // simulation parameters for smith_disc.xcos N_var = 0; C = 0; D = 1; N = 1; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bdp,Ap] = cosfil_ip(Bd,A); // Bd/Ad [zkdp1,zkdp2] = cosfil_ip(zkd,1); // zkd/1 [mzkdp1,mzkdp2] = cosfil_ip(mzkd,1); // mzkd/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 24 fields: save_id: gallery23 name: Ex11_4 description: 'Digital Control (Author: K. M. Moudgalya), 11) Minimum Variance Control, 11.4) 1st control problem by MacGregor' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;text_f;tows_c media: gallery23.png script_dump: '// MacGregor''s first control problem, discussed in Example 11.4 on page 213. // 11.4 // Minimum variance control law design, given by Eq. 11.40 on page 413. // 11.5 // function [S,dS,R,dR] = mv(A,dA,B,dB,C,dC,k,int) // implements the minimum variance controller // if int>=1, integrated noise is assumed; otherwise, // it is not integrated noise function [S,dS,R,dR] = mv(A,dA,B,dB,C,dC,k,int1) zk = zeros(1,k+1); zk(k+1) = 1; if int1>=1, [A,dA] = polmul([1 -1],1,A,dA); end [Fk,dFk,Ek,dEk] = xdync(zk,k,A,dA,C,dC); [Gk,dGk] = polmul(Ek,dEk,B,dB); S = Fk; dS = dFk; R = Gk; dR = dGk; endfunction; // Calculation of closed loop transfer functions // 11.6 // function [Nu,dNu,Du,dDu,Ny,dNy,Dy,dDy,yvar,uvar] = ... // cl(A,dA,B,dB,C,dC,k,S,dS,R,dR,int) // int>=1 means integrated noise and control law: // delta u = - (S/R)y // Evaluates the closed loop transfer function and // variances of input and output function [Nu,dNu,Du,dDu,Ny,dNy,Dy,dDy,yvar,uvar] = ... cl(A,dA,B,dB,C,dC,k,S,dS,R,dR,int1) [zk,dzk] = zpowk(k); [BS,dBS] = polmul(B,dB,S,dS); [zBS,dzBS] = polmul(zk,dzk,BS,dBS); [RA,dRA] = polmul(R,dR,A,dA); if int1>=1, [RA,dRA] = polmul(RA,dRA,[1 -1],1); end [D,dD] = poladd(RA,dRA,zBS,dzBS); [Ny,dNy] = polmul(C,dC,R,dR); [Nu,dNu] = polmul(C,dC,S,dS); [Nu,dNu,Du,dDu,uvar] = tfvar(Nu,dNu,D,dD); [Ny,dNy,Dy,dDy,yvar] = tfvar(Ny,dNy,D,dD); endfunction; // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction function [C,degC] = poladd(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= cB | rA ~= rB error(''poladd: Inconsistent dimensions''); end degC = max(degA,degB); if degC >= degA A = [A zeros(rA,(degC-degA)*cA)]; end if degC >= degB B = [B zeros(rB,(degC-degB)*cB)]; end C = A+B; endfunction; // Cancellation of common factors and determination of covariance // 11.7 // function [N,dN,D,dD,yvar] = tfvar(N,dN,D,dD) // N and D polynomials in z^{-1} form; discrete case function [N,dN,D,dD,yvar] = tfvar(N,dN,D,dD) [N,dN,D,dD] = l2r(N,dN,D,dD); N = N/D(1); D = D/D(1); LN = length(N); LD = length(D); D1 = D; if LD a is not passed // System is discrete => a = -1 // System is discretized (sampled system) => a = Ts // Uses syslin function trfu = tf(num,den,a) if argn(2) == 2 d = ''c''; elseif a == -1 d = ''d''; else d = a end; num = clean(num); den = clean(den); num1 = poly(num(length(num):-1:1),''x'',''coeff''); den1 = poly(den(length(den):-1:1),''x'',''coeff''); trfu = syslin(d,num1,den1); endfunction; //User defined equivalent function to Matlab covar function //For discrete time domain only //Uses Lyapunov''s equation for computation //W: noise intensity (scalar) //Matlab result for unstable systems: //Warning: Unstable models have infinite covariance function P = covar_m(sys,W) a = roots(sys(''den'')); b = length(a); c = abs(a) > 1; if b ~= 0 then for i = 1:b if c(i) == %t then disp(''Warning: System being unstable has infinite covariance''); P = %inf; else s = tf2ss(sys); [A,B,C,D] = s(2:5); //Sylvester and Lyapunov solver task = 2; flag = [1 0]; tran = 1; Q1 = -B*W*B''; Q = linmeq(task,A,Q1,flag,tran) P = C*Q*C'' + D*W*D''; end; end; else s = tf2ss(sys); [A,B,C,D] = s(2:5); //Sylvester and Lyapunov solver task = 2; flag = [1 0]; tran = 1; Q1 = -B*W*B''; Q = linmeq(task,A,Q1,flag,tran) P = C*Q*C'' + D*W*D''; end; endfunction; //if d==0 | c==%f // disp(''Calc''); //else // disp(''Unstable''); //end; // Above logic can also solve our purpose // But it gives incorrect answer if roots are [1 -1 1] or // [1 -1 -1] .... // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // MacGregor''s first control problem A = [1 -1.4 0.45]; dA = 2; C = [1 -0.5]; dC = 1; B = 0.5*[1 -0.9]; dB = 1; k = 1; int1 = 0; [Sc,dSc,Rc,dRc] = mv(A,dA,B,dB,C,dC,k,int1); [Nu,dNu,Du,dDu,Ny,dNy,Dy,dDy,yvar,uvar] = ... cl(A,dA,B,dB,C,dC,k,Sc,dSc,Rc,dRc,int1); // Simulation parameters for stb_disc.xcos Tc = Sc; gamm = 1; [zk,dzk] = zpowk(k); D = 1; N_var = 1; Ts = 1; st = 0; t_init = 0; t_final = 1000; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 25 fields: save_id: gallery24 name: Ex7_6 description: 'Digital Control (Author: K. M. Moudgalya), 7) Structures and Specifications, 7.6) Verification of performance of lead controller on antenna system' save_time: 2025-05-30 12:29:41+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;dlr;samphold_m;split_f;step_function;super_f;text_f;tows_c media: gallery24.png script_dump: '// Verification of performance of lead controller on antenna system, as discussed in Example 7.3. // 7.6 // Continuous time antenna model a = 0.1; F = [0 1;0 -a]; g = [0; a]; c = [1 0]; d = 0; Ga = syslin(''c'',F,g,c,d); [ds,num,den] = ss2tf(Ga); Num = clean(num); Den = clean(den); Ts = 0.2; G = dscr(Ga,Ts); // lead controller beta1 = 0.8; N = [1 -0.9802]*(1-beta1)/(1-0.9802); Rc = [1 -beta1]; // simulation parameters using g_s_cl2.cos gamm = 1; Sc = 1; Tc = 1; C = 0; D = 1; st = 1; st1 = 0; t_init = 0; t_final = 20; t = 0.5; // u1: -4 to 11 // y1: 0 to 1.4 // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // N/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 26 fields: save_id: gallery25 name: Ex7_7 description: 'Digital Control (Author: K. M. Moudgalya), 7) Structures and Specifications, 7.7) Illustration of system type' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;text_f;tows_c media: gallery25.png script_dump: '// Illustration of system type, as explained in Example 7.10 on page 275. // 7.7 // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function b = indep(S,gap) // determines the first row that is dependent on the previous rows of S. // The coefficients of dependence is returned in b function b = indep( S,gap) if argn(2) == 1 gap = 1.0e8; end [rows,cols] = size(S); ind = 1; i = 2; eps = 2.2204e-016; while ind & i <= rows sigma = svd(S(1:i,:)); len = length(sigma); if(sigma(len)/sigma(1) < (eps*max(i,cols))) ind =0; else shsig = [sigma(2:len);sigma(len)]; if or( (sigma ./shsig) > gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // Solution to Aryabhatta''s identity arising in PID controller design, namely Eq. 9.37 on page 363. // 9.20 function [Rc,Sc] = pp_pid(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity dB = length(B) - 1; dA = length(A) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(B,dB,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(A,dA,Delta,dDelta); dphi = length(phi)-1; [Sc,dSc,R,dR] = xdync(N,dN,D,dD,phi,dphi); Rc = convol(R,Delta); endfunction; // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Plant B = 1; A = [1 -1]; zk = [0 1]; Ts = 1; k = 1; // Value of k absent in original code // Specify closed loop characteristic polynomial phi = [1 -0.5]; // Design the controller reject_ramps = 1; if reject_ramps == 1, Delta = [1 -1]; // to reject ramps another Delta else Delta = 1; // steps can be rejected by plant itself end [Rc,Sc] = pp_pid(B,A,k,phi,Delta); // parameters for simulation using stb_disc.mdl Tc = Sc; gamm = 1; N = 1; C = 0; D = 1; N_var = 0; st = 1; t_init = 0; t_final = 20; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D // Give appropriate path //xcos(''stb_disc.xcos'');' - model: saveAPI.gallery pk: 27 fields: save_id: gallery26 name: Ex9_10 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.10) Pole placement controller IBM Lotus Domino server' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;tows_c media: gallery26.png script_dump: '// Pole placement controller IBM Lotus Domino server, discussed in Example 9.9 on page 341. // 9.10 // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Control of IBM lotus domino server // Transfer function B = 0.47; A = [1 -0.43]; k = 1; [zk,dzk] = zpowk(k); // Transient specifications rise = 10; epsilon = 0.01; Ts = 1; phi = desired(Ts,rise,epsilon); // Controller design Delta = [1 -1]; // internal model of step used [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta); // Simulation parameters for stb_disc.xcos st = 1; // desired change t_init = 0; // simulation start time t_final = 40; // simulation end time C = 0; D = 1; N_var = 0; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 28 fields: save_id: gallery27 name: Ex9_11 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.11) Pole placement controller for motor problem' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clss;cscope;dlr;rand_m;samphold_m;split_f;step_function;super_f;tows_c media: gallery27.png script_dump: '// Pole placement controller for motor problem, discussed in Example 9.10 on page 343. // 9.11 // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Motor control problem // Transfer function a1 = [-1 0; 1 0]; b1 = [1; 0]; c1 = [0 1]; d1 = 0; G = syslin(''c'',a1,b1,c1,d1); Ts = 0.25; [B,A,k] = myc2d(G,Ts); // Transient specifications rise = 3; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design Delta = 1; // No internal model of step used [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta); // simulation parameters for c_ss_cl.xcos st = 1; //desired change in position t_init = 0; //simulation start time t_final = 10; //simulation end time xInitial = [0 0]; //initial conditions N = 1; C = 0; D = 1; N_var = 0; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 29 fields: save_id: gallery28 name: Ex9_14 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.14) Controller design' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;dlr;samphold_m;split_f;step_function;super_f;text_f;tows_c media: gallery28.png script_dump: '// Controller design for the case study presented in Example 9.12 on page 347. // 9.14 //User defined function //Forms a transfer function //Scilab: Co efficients are given in increasing power of variable //Matlab: Co efficients are given in decreasing power of variable //Hence co efficients are flipped here //Input arguments: (1) Numerator co efficients(decreasing order) //(2) Denominator co efficients //(3) Variable to specify domain // Updated (30-11-06) // System is continuous => a is not passed // System is discrete => a = -1 // System is discretized (sampled system) => a = Ts // Uses syslin function trfu = tf(num,den,a) if argn(2) == 2 d = ''c''; elseif a == -1 d = ''d''; else d = a end; num = clean(num); den = clean(den); num1 = poly(num(length(num):-1:1),''x'',''coeff''); den1 = poly(den(length(den):-1:1),''x'',''coeff''); trfu = syslin(d,num1,den1); endfunction; // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // Pole placement controller without intra sample oscillations, as discussed in Sec. 9.5. // 9.13 // function [Rc,Sc,Tc,gamma,phit] = pp_im2(B,A,k,phi,Delta,a) // 2-DOF PP controller with internal model of Delta and without // hidden oscillations function [Rc,Sc,Tc,gamm,phit] = pp_im2(B,A,k,phi,Delta,a) if argn(2) == 5, a = 1; end dphi = length(phi)-1; // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A,a); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B,a); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); // Total characteristic polynomial phit = convol(phi,convol(Ag,Bg)); endfunction; // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction num = 200; den = convol([0.05 1],[0.05 1]); den = convol([10 1],den); G = tf(num,den); Ts = 0.025; num = G(''num''); den = G(''den''); // iodel = 0; [B,A,k] = myc2d(G,Ts); [zk,dzk] = zpowk(k); //int1 = 0; // Transient specifications a = 0.9; rise = 0.24; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design Delta = [1 -1]; // internal model of step is present [Rc,Sc,Tc,gamm] = pp_im2(B,A,k,phi,Delta,a); // margin calculation Lnum = convol(Sc,convol(B,zk)); Lden = convol(Rc,A); L = tf(Lnum,Lden,Ts); // Gm = g_margin(L); //---- Does not match --------------- (in dB) Pm = p_margin(L); //---- Convergence problem --------------- (in degree) num1 = 100; den1 = [10 1]; Gd = tf(num1,den1); //------- [C,D,k1] = myc2d(Gd,Ts); [zk,dzk] = zpowk(k); C = convol(C,zk); // simulation parameters g_s_cl2.xcos ------------ N = 1; st = 1; // desired change in setpoint st1 = 0; // magnitude of disturbance t_init = 0; // simulation start time t_final = 1.5; // simulation end time [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // N/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 30 fields: save_id: gallery29 name: Ex9_15_1 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.15) Evaluation of continuous time controller' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;split_f;step_function;super_f;tows_c media: gallery29.png script_dump: '// Evaluation of continuous time controller for the case study presented in Example 9.13 on page 349. // 9.15 //User defined function //Forms a transfer function //Scilab: Co efficients are given in increasing power of variable //Matlab: Co efficients are given in decreasing power of variable //Hence co efficients are flipped here //Input arguments: (1) Numerator co efficients(decreasing order) //(2) Denominator co efficients //(3) Variable to specify domain // Updated (30-11-06) // System is continuous => a is not passed // System is discrete => a = -1 // System is discretized (sampled system) => a = Ts // Uses syslin function trfu = tf(num,den,a) if argn(2) == 2 d = ''c''; elseif a == -1 d = ''d''; else d = a end; num = clean(num); den = clean(den); num1 = poly(num(length(num):-1:1),''x'',''coeff''); den1 = poly(den(length(den):-1:1),''x'',''coeff''); trfu = syslin(d,num1,den1); endfunction; // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction num = 200; den = convol([0.05 1],[0.05 1]); den = convol([10 1],den); G = tf(num,den); Ts = 0.005; [B,A,k] = myc2d(G,Ts); [zk,dzk] = zpowk(k); //int = 0; // Sigurd''s feedback controller'' numb = 0.5*convol([1 2],[0.05 1]); denb = convol([1 0],[0.005 1]); Gb = tf(numb,denb); [Sb,Rb,kb] = myc2d(Gb,Ts); [zkb,dzkb] = zpowk(kb); Sb = convol(Sb,zkb); // Sigurd''s feed forward controller'' numf = [0.5 1]; denf = convol([0.65 1],[0.03 1]); Gf = tf(numf,denf); [Sf,Rf,kf] = myc2d(Gf,Ts); [zkf,dzkf] = zpowk(kf); Sf = convol(Sf,zkf); // Margins simp_mode(%f); L = G*Gb; // Gm = g_margin(L); // ------ Pm = p_margin(L); // ------ Lnum = convol(Sb,convol(zk,B)); Lden = convol(Rb,A); L = tf(Lnum,Lden,Ts); // DGm = g_margin(L); // ------ DPm = p_margin(L); // ------ // Noise num1 = 100; den1 = [10 1]; // simulation parameters for // entirely continuous simulation: g_s_cl3.xcos // hybrid simulation: g_s_cl6.xcos st = 1; // desired change in setpoint st1 = 0; t_init = 0; // simulation start time t_final = 5; // simulation end time num = polyno(num,''s''); den = polyno(den,''s''); Numb = polyno(numb,''s''); Denb = polyno(denb,''s''); Numf = polyno(numf,''s''); Denf = polyno(denf,''s''); Num1 = polyno(num1,''s''); Den1 = polyno(den1,''s''); [Sbp,Rbp] = cosfil_ip(Sb,Rb); [Sfp,Rfp] = cosfil_ip(Sf,Rf);' - model: saveAPI.gallery pk: 31 fields: save_id: gallery30 name: Ex9_15_2 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.15) Evaluation of continuous time controller' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;dlr;samphold_m;split_f;step_function;super_f;tows_c media: gallery30.png script_dump: '// Evaluation of continuous time controller for the case study presented in Example 9.13 on page 349. // 9.15 //User defined function //Forms a transfer function //Scilab: Co efficients are given in increasing power of variable //Matlab: Co efficients are given in decreasing power of variable //Hence co efficients are flipped here //Input arguments: (1) Numerator co efficients(decreasing order) //(2) Denominator co efficients //(3) Variable to specify domain // Updated (30-11-06) // System is continuous => a is not passed // System is discrete => a = -1 // System is discretized (sampled system) => a = Ts // Uses syslin function trfu = tf(num,den,a) if argn(2) == 2 d = ''c''; elseif a == -1 d = ''d''; else d = a end; num = clean(num); den = clean(den); num1 = poly(num(length(num):-1:1),''x'',''coeff''); den1 = poly(den(length(den):-1:1),''x'',''coeff''); trfu = syslin(d,num1,den1); endfunction; // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction num = 200; den = convol([0.05 1],[0.05 1]); den = convol([10 1],den); G = tf(num,den); Ts = 0.005; [B,A,k] = myc2d(G,Ts); [zk,dzk] = zpowk(k); //int = 0; // Sigurd''s feedback controller'' numb = 0.5*convol([1 2],[0.05 1]); denb = convol([1 0],[0.005 1]); Gb = tf(numb,denb); [Sb,Rb,kb] = myc2d(Gb,Ts); [zkb,dzkb] = zpowk(kb); Sb = convol(Sb,zkb); // Sigurd''s feed forward controller'' numf = [0.5 1]; denf = convol([0.65 1],[0.03 1]); Gf = tf(numf,denf); [Sf,Rf,kf] = myc2d(Gf,Ts); [zkf,dzkf] = zpowk(kf); Sf = convol(Sf,zkf); // Margins simp_mode(%f); L = G*Gb; // Gm = g_margin(L); // ------ Pm = p_margin(L); // ------ Lnum = convol(Sb,convol(zk,B)); Lden = convol(Rb,A); L = tf(Lnum,Lden,Ts); // DGm = g_margin(L); // ------ DPm = p_margin(L); // ------ // Noise num1 = 100; den1 = [10 1]; // simulation parameters for // entirely continuous simulation: g_s_cl3.xcos // hybrid simulation: g_s_cl6.xcos st = 1; // desired change in setpoint st1 = 0; t_init = 0; // simulation start time t_final = 5; // simulation end time num = polyno(num,''s''); den = polyno(den,''s''); Numb = polyno(numb,''s''); Denb = polyno(denb,''s''); Numf = polyno(numf,''s''); Denf = polyno(denf,''s''); Num1 = polyno(num1,''s''); Den1 = polyno(den1,''s''); [Sbp,Rbp] = cosfil_ip(Sb,Rb); [Sfp,Rfp] = cosfil_ip(Sf,Rf);' - model: saveAPI.gallery pk: 32 fields: save_id: gallery31 name: Ex9_16 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.16) System type with 2 DOF controller' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;tows_c media: gallery31.png script_dump: '// System type with 2-DOF controller. It is used to arrive at the results Example 9.14. // 9.16 // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction B = 1; A = [1 -1]; k = 1; zk = zpowk(k); Ts = 1; phi = [1 -0.5]; Delta = 1; // Choice of internal model of step [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta); // simulation parameters for stb_disc.xcos st = 1; // desired step change t_init = 0; // simulation start time t_final = 20; // simulation end time xInitial = [0 0]; C = 0; D = 1; N_var = 0; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 33 fields: save_id: gallery32 name: Ex9_17 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.17) Illustrating the benefit of cancellation' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;tows_c media: gallery32.png script_dump: '// Illustrating the benefit of cancellation. It is used to arrive at the results of Example 9.15. // 9.17 // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Solution to Aryabhatta''s identity arising in PID controller design, namely Eq. 9.37 on page 363. // 9.20 function [Rc,Sc] = pp_pid(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity dB = length(B) - 1; dA = length(A) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(B,dB,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(A,dA,Delta,dDelta); dphi = length(phi)-1; [Sc,dSc,R,dR] = xdync(N,dN,D,dD,phi,dphi); Rc = convol(R,Delta); endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // test problem to demonstrate benefits of 2_dof // Ts = 1; B = [1 0.9]; A = conv([1 -1],[1 -0.8]); k = 1; Ts = 1; k = 1; B = convol([1 0.9],[1 -0.8]); A = convol([1 -1],[1 -0.5]); // closed loop characteristic polynomial phi = [1 -1 0.5]; Delta = 1; // Choice of internal model of step control = 1; if control == 1, // 1-DOF with no cancellation [Rc,Sc] = pp_pid(B,A,k,phi,Delta); Tc = Sc; gamm = 1; else // 2-DOF [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta); end // simulation parameters for stb_disc.mdl [zk,dzk] = zpowk(k); st = 1; // desired step change t_init = 0; // simulation start time t_final = 20; // simulation end time xInitial = [0 0]; C = 0; D = 1; N_var = 0; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 34 fields: save_id: gallery33 name: Ex9_18 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.18) Anti windup control of IBM Lotus Domino server' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;saturation;split_f;step_function;summation;super_f;text_f;tows_c media: gallery33.png script_dump: '// Anti windup control (AWC) of IBM Lotus Domino server, studied in Example 9.16 on page 357. It can be used for the follwoing situations: with and without saturation, and with and without AWC. // 9.18 // Pole placement controller without intra sample oscillations, as discussed in Sec. 9.5. // 9.13 // function [Rc,Sc,Tc,gamma,phit] = pp_im2(B,A,k,phi,Delta,a) // 2-DOF PP controller with internal model of Delta and without // hidden oscillations function [Rc,Sc,Tc,gamm,phit] = pp_im2(B,A,k,phi,Delta,a) if argn(2) == 5, a = 1; end dphi = length(phi)-1; // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A,a); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B,a); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); // Total characteristic polynomial phit = convol(phi,convol(Ag,Bg)); endfunction; // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction function [C,degC] = poladd(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= cB | rA ~= rB error(''poladd: Inconsistent dimensions''); end degC = max(degA,degB); if degC >= degA A = [A zeros(rA,(degC-degA)*cA)]; end if degC >= degB B = [B zeros(rB,(degC-degB)*cB)]; end C = A+B; endfunction; // Transfer function B = 0.47; A = [1 -0.43]; k = 1; [zk,dzk] = zpowk(k); // Transient specifications rise = 10; epsilon = 0.01; Ts = 1; phi = desired(Ts,rise,epsilon); // Controller design delta = [1 -1]; // internal model of step used [Rc,Sc,Tc,gamm,F] = pp_im2(B,A,k,phi,delta); // Study of Antiwindup Controller // Set key between 1 and 4 // key = 1: Simulate without any saturation limits // key = 2: Simulate saturation, but do not use AWC // key = 3: Simulate saturation with AWC in place // key = 4: Simulate with AWC, without saturation limits key=1 if key ==0 disp(''Invalid choice''); return; elseif key == 1 U = 2; L = -2; P = 1; F = Rc; E = 0; PSc = Sc; PTc = Tc; elseif key == 2 U = 1; L = -1; P = 1; F = Rc; E = 0; PSc = Sc; PTc = Tc; else if key == 3 // Antiwindup controller and with saturation U = 1; L = -1; elseif key == 4 // Antiwindup controller, but no saturation U = 2; L = -2; else disp(''Invalid choice''); return; end P = A; dF = length(F) - 1; PRc = convol(P,Rc); dPRc = length(PRc) - 1; [E,dE] = poladd(F,dF,-PRc,dPRc); PSc = convol(P,Sc); PTc = convol(P,Tc); end // Setting up simulation parameters for stb_disc_sat t_init = 0; // first step begins st = 1; // height of first step t_init2 = 500; // second step begins st2 = -2; // height of second step t_final = 1000; // simulation end time st1 = 0; // no disturbance input C = 0; D = 1; N_var = 0; [PTcp1,PTcp2] = cosfil_ip(PTc,1); // PTc/1 [Fp1,Fp2] = cosfil_ip(1,F); // 1/F [Ep,Fp] = cosfil_ip(E,F); // E/F [PScp1,PScp2] = cosfil_ip(PSc,1); // PSc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 35 fields: save_id: gallery34 name: Ex9_19 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.19) Demonstration of usefulness of negative PID parameters' save_time: 2025-05-30 12:29:41+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;dlr;ramp;rand_m;samphold_m;split_f;step_function;super_f;switch_f;text_f;time_delay;tows_c media: gallery34.png script_dump: '// Demonstration of usefulness of negative PID parameters, discussed in Example 9.17 on page 361. // 9.19 funcprot(0) function Hd=iodelay(H,d) if or(size(H.num)<>size(d)) then error(''Dimension mismatch''),end Hd=mlist([''rd'',''H'',''iodelay''],H,d) endfunction //element wise product overloading functions function H=%rd_x_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],H1.H.*H2.H,H1.iodelay+ H2.iodelay) endfunction function H=%rd_x_r(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],H1.H.*H2,H1.iodelay) endfunction function H=%r_x_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],H1.*H2.H,H2.iodelay) endfunction function H=%rd_x_s(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],H1.H.*H2,H1.iodelay) endfunction function H=%s_x_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],H1.*H2.H,H2.iodelay) endfunction //column concatenation overloading functions function H=%rd_c_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1.H H2.H],[H1.iodelay,H2.iodelay]) endfunction function H=%rd_c_r(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1.H H2],[H1.iodelay,zeros(H2.num)]) endfunction function H=%r_c_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1 H2.H],[zeros(H1.num),H2.iodelay]) endfunction function H=%rd_c_s(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1.H H2],[H1.iodelay,zeros(H2.num)]) endfunction function H=%s_c_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1 H2.H],[zeros(H1.num),H2.iodelay]) endfunction //row concatenation overloading functions function H=%rd_f_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1.H;H2.H],[H1.iodelay;H2.iodelay]) endfunction function H=%rd_f_r(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1.H;H2],[H1.iodelay;zeros(H2.num)]) endfunction function H=%r_f_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1;H2.H],[zeros(H1.num);H2.iodelay]) endfunction function H=%rd_f_s(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1.H;H2],[H1.iodelay;zeros(H2.num)]) endfunction function H=%s_f_rd(H1,H2) // Author: Serge Steer, Copyright INRIA H=mlist([''rd'',''H'',''iodelay''],[H1;H2.H],[zeros(H1.num);H2.iodelay]) endfunction //matrix product overloading functions function H=%rd_m_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay D2=H2.iodelay D=D1*D2; for k=1;size(D2,2) for l=1:size(D1,1) d=D1(l,:)+(D2(:,k)'') if or(d(1)<>d) then error(''Delays mismatched''),end D(l,k)=d end end H=mlist([''rd'',''H'',''iodelay''],H1.H*H2.H,D) endfunction function H=%rd_m_r(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay for l=1:size(D1,1) if or(D1(l,1)<>D1(l,:)) then error(''Delays mismatched''),end end H=mlist([''rd'','''',''iodelay''],H1.H*H2,D1) endfunction function H=%rd_m_s(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay for l=1:size(D1,1) if or(D1(l,1)<>D1(l,:)) then error(''Delays mismatched''),end end H=mlist([''rd'',''H'',''iodelay''],H1.H*H2,D1) endfunction function H=%r_m_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D2=H2.iodelay for l=1:size(D2,2) if or(D2(1,l)<>D2(:,l)) then error(''Delays mismatched''),end end H=mlist([''rd'',''H'',''iodelay''],H1*H2.H,D2) endfunction function H=%s_m_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D2=H2.iodelay for l=1:size(D2,2) if or(D2(1,l)<>D2(:,l)) then error(''Delays mismatched''),end end H=mlist([''rd'',''H'',''iodelay''],H1*H2.H,D2) endfunction //Addition overloading functions function H=%rd_a_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay D2=H2.iodelay if or(D1<>D2) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1.H+H2.H,D1) endfunction function H=%rd_a_r(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay if or(D1<>0) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1.H+H2,D1) endfunction function H=%rd_a_s(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay if or(D1<>0) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1.H+H2,D1) endfunction function H=%r_a_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D2=H2.iodelay if or(D2<>0) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1+H2.H,D2) endfunction //Substraction overloading functions function H=%rd_a_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay D2=H2.iodelay if or(D1<>D2) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1.H-H2.H,D1) endfunction function H=%rd_a_r(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay if or(D1<>0) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1.H-H2,D1) endfunction function H=%rd_a_s(H1,H2) // Author: Serge Steer, Copyright INRIA D1=H1.iodelay if or(D1<>0) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1.H-H2,D1) endfunction function H=%r_a_rd(H1,H2) // Author: Serge Steer, Copyright INRIA D2=H2.iodelay if or(D2<>0) then error(''Delay mismatch''),end H=mlist([''rd'',''H'',''iodelay''],H1-H2.H,D2) endfunction //extraction overloading functions function H=%rd_e(varargin) // Author: Serge Steer, Copyright INRIA H=varargin($) Hh= H.H;Hh.num=Hh.num(varargin(1:$-1));Hh.den=Hh.den(varargin(1:$-1)); H.H=Hh H.iodelay=H.iodelay(varargin(1:$-1)) endfunction //insertion overloading functions function H=%rd_i_rd(varargin) // Author: Serge Steer, Copyright INRIA H=varargin($) Hfrom=varargin($-1) Hh= H.H Hh.num(varargin(1:$-2))=Hfrom.H.num Hh.den(varargin(1:$-2))=Hfrom.H.den H.H=Hh H.iodelay(varargin(1:$-2))=Hfrom.iodelay endfunction function H=%r_i_rd(varargin) // Author: Serge Steer, Copyright INRIA H=varargin($) Hfrom=varargin($-1) Hh= H.H Hh.num(varargin(1:$-2))=Hfrom.num Hh.den(varargin(1:$-2))=Hfrom.den H.H=Hh H.iodelay(varargin(1:$-2))=zeros(Hfrom.num) endfunction function H=%s_i_rd(varargin) // Author: Serge Steer, Copyright INRIA H=varargin($) Hfrom=varargin($-1) Hh= H.H Hh.num(varargin(1:$-2))=Hfrom Hh.den(varargin(1:$-2))=ones(Hfrom) H.H=Hh H.iodelay(varargin(1:$-2))=zeros(Hfrom) endfunction function H=%rd_i_r(varargin) // Author: Serge Steer, Copyright INRIA Hh=varargin($) Hfrom=varargin($-1) Hh.num(varargin(1:$-2))=Hfrom.H.num Hh.den(varargin(1:$-2))=Hfrom.H.den D=zeros(Hh.num) D(varargin(1:$-2))=Hfrom.iodelay H=mlist([''rd'',''H'',''iodelay''],Hh,D) endfunction function H=%rd_i_s(varargin) // Author: Serge Steer, Copyright INRIA num=varargin($);den=ones(num) Hfrom=varargin($-1) num(varargin(1:$-2))=Hfrom.H.num den(varargin(1:$-2))=Hfrom.H.den D=zeros(num) D(varargin(1:$-2))=Hfrom.iodelay H=mlist([''rd'',''H'',''iodelay''],rlist(num,den,''c''),D) endfunction //transpostion overloading function function H=%rd_t(H) // Author: Serge Steer, Copyright INRIA H.H=H.H'' H.iodelay=H.iodelay'' endfunction //string overloading function function txt=%rd_string(H) // Author: Serge Steer, Copyright INRIA r=H.H N=string(r.num) D=string(r.den) ln=max(matrix(length(N),2,-1),''r'') ld=max(matrix(length(D),2,-1),''r'') l=max(ln,ld) [m,n]=size(r.num); S=emptystr(m,n) kz=find(H.iodelay==0);//zero delay entries w=''exp(''+string(-H.iodelay)+''*s)*'';w(kz)=''''; for i=1:m*n s=2*i-1:2*i pw=part('' '',1:length(w(i))) N(s)=pw+part('' '',1:(l(i)-ln(i))/2)+N(s) D(s)=pw+part('' '',1:(l(i)-ld(i))/2)+D(s) S(i) =w(i)+part(''-'',ones(1,l(i))) end txt=emptystr(5*m,n); txt(1:5:$,:)=N(1:2:$,:) txt(2:5:$,:)=N(2:2:$,:) txt(3:5:$,:)=S(1:$,:) txt(4:5:$,:)=D(1:2:$,:) txt(5:5:$,:)=D(2:2:$,:) endfunction //Display overloading function function %rd_p(H) // Author: Serge Steer, Copyright INRIA //used to display rational fraction with complex coefficients //The real case is hard coded // Copyright INRIA T=string(H) l=max(length(T),''r'') Te=emptystr(size(T,1),1) for k=1:size(T,2) Te=Te+part(T(:,k),1:l(k)+1)+'' '' end mprintf("%s\n",Te) endfunction //frequency response computation overloading function [frq,repf,splitf]=repfreq(varargin) // Author: Serge Steer, Copyright INRIA H=varargin(1) autolib.repfreq if typeof(H)==''rd'' then D=H.iodelay varargin(1)=H.H [frq,repf,splitf]=repfreq(varargin(:)) w=-2*%i*%pi*frq; for k=1:size(D,''*'') repf(k,:)=repf(k,:).*exp(D(k)*w) end else [frq,repf,splitf]=repfreq(varargin(:)) end endfunction //bode plot computation overloading function bode(varargin) // Author: Serge Steer, Copyright INRIA H=varargin(1) xdesslib.bode if typeof(H)==''rd'' then if type(varargin($))==10 then //a comment cm=varargin($);varagin($)=null() else cm='''' end D=H.iodelay varargin(1)=H.H [frq,repf,splitf]=repfreq(varargin(1:$)) w=-2*%i*%pi*frq; for k=1:size(D,''*'') repf(k,:)=repf(k,:).*exp(D(k)*w) end bode(frq,repf) else bode(varargin(:)) end endfunction //nyquist plot computation overloading function nyquist(varargin) // Author: Serge Steer, Copyright INRIA H=varargin(1) xdesslib.nyquist if typeof(H)==''rd'' then if type(varargin($))==10 then //a comment cm=varargin($);varagin($)=null() else cm='''' end D=H.iodelay varargin(1)=H.H [frq,repf,splitf]=repfreq(varargin(1:$)) w=-2*%i*%pi*frq; for k=1:size(D,''*'') repf(k,:)=repf(k,:).*exp(D(k)*w) end nyquist(frq,repf) else nyquist(varargin(:)) end endfunction // Discretizing a tf with delay // Exact solution // Applicable for a 1st order system // Ref.: pg.287,Digital Control,Prof.Kannan Moudgalya // D: Delay // TF: e^(-Ds) OR e^(-Ds) // ------------ ------------ (gen.) // tau*s + 1 tau*s + a //D = kTs + D'' (gen.) // G: TF with delay component // G1: TF with zero delay // Required because G cannot be directly used in Scilab // Coefficients are returned for ascending powers of z^-1 function [B,A,k1] = delc2d(G,G1,Ts) D = G.iodelay; d = coeff(G1(''den'')); if d(1) == 1 tau = d(2); mu = 1; else tau = d(2)/d(1); mu = 1/d(1); end; k = floor(D/Ts); Dpri = D - k*Ts; Dis = ((%z*(1 - (exp(-(Ts - Dpri)/tau)) ) )+ (exp(-(Ts - Dpri)/tau) - exp(-Ts/tau) ))/ ((%z^(k+1))*(%z - exp(-Ts/tau))) Dis1 = Dis*mu; disp(''Warning: Exact discretization of first order system only''); k1 = degree(Dis1(''den'')) - degree(Dis1(''num'')); B = coeff(Dis1(''num'')); A = coeff(Dis1(''den'')); B = flip(B); A = flip(A); endfunction; // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Solution to Aryabhatta''s identity arising in PID controller design, namely Eq. 9.37 on page 363. // 9.20 function [Rc,Sc] = pp_pid(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity dB = length(B) - 1; dA = length(A) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(B,dB,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(A,dA,Delta,dDelta); dphi = length(phi)-1; [Sc,dSc,R,dR] = xdync(N,dN,D,dD,phi,dphi); Rc = convol(R,Delta); endfunction; // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; //User defined function //Forms a transfer function //Scilab: Co efficients are given in increasing power of variable //Matlab: Co efficients are given in decreasing power of variable //Hence co efficients are flipped here //Input arguments: (1) Numerator co efficients(decreasing order) //(2) Denominator co efficients //(3) Variable to specify domain // Updated (30-11-06) // System is continuous => a is not passed // System is discrete => a = -1 // System is discretized (sampled system) => a = Ts // Uses syslin function trfu = tf(num,den,a) if argn(2) == 2 d = ''c''; elseif a == -1 d = ''d''; else d = a end; num = clean(num); den = clean(den); num1 = poly(num(length(num):-1:1),''x'',''coeff''); den1 = poly(den(length(den):-1:1),''x'',''coeff''); trfu = syslin(d,num1,den1); endfunction; // 10.5 function b = flip(a) b = a(length(a):-1:1); endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Discretize the continuous plant num = 1; den = [2 1]; tau = 0.5; G1 = tf(num,den); G = iodelay(G1,tau); Ts = 0.5; [B,A,k] = delc2d(G,G1,Ts); // Specify transient requirements epsilon = 0.05; rise = 5; phi = desired(Ts,rise,epsilon); // Design the controller Delta = [1 -1]; [Rc,Sc] = pp_pid(B,A,k,phi,Delta); // parameters for simulation using g_s_cl Tc = Sc; gamm = 1; N = 1; C = 0; D = 1; N_var = 0; st = 1; t_init = 0; t_final = 20; t = 0.5; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // N/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D Num = G1.num; Den = G1.den;' - model: saveAPI.gallery pk: 36 fields: save_id: gallery35 name: Ex9_1_1 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.1) Pole placement controller for magnetically suspended ball problem' save_time: 2025-05-08 12:24:26+00:00 book: 2048 data_dump: blocks: clkoutv_f;clksplit_f;clock_c;clr;cscope;dlr;samphold_m;split_f;step_function;summation;super_f;text_f;tows_c media: gallery35.png script_dump: '// Pole placement controller for magnetically suspended ball problem, discussed in Example 9.3 on page 331. // 9.1 // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.2. // 9.3 // function [goodpoly,badpoly] = polsplit2(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. // Input is a polynomial in increasing degree of z^{-1} // Optional input is a, where a <= 1. // Factor that has roots of z^{-1} outside a is called // good and the rest bad. // If a is not specified, it will be assumed as 1-1.0e-5 function [goodpoly,badpoly] = polsplit2(fac,a) if argn(2) == 1, a = 1-1.0e-5; end if a>1 error(''good polynomial is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts1 = roots(fac1); rts = rts1(length(rts1):-1:1); // extract good and bad roots badindex = find(abs(rts)>=a); // mtlb_find has been replaced by find badpoly = coeff(poly((rts(badindex)),"z","roots")); goodindex = find(abs(rts) 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // Design of 2-DOF pole placement controller, as discussed in Sec. 9.2. // 9.5 // function [Rc,Sc,Tc,gamma] = pp_basic(B,A,k,phi) // calculates pole placement controller function [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit2(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit2(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dphi = length(phi) - 1; [S1,dS1,R1,dR1] = xdync(N,dN,Ab,dAb,phi,dphi); // Determination of control law Rc = convol(Bg,R1); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Magnetically suspended ball problem // Operating conditions M = 0.05; L = 0.01; R = 1; K = 0.0001; g = 9.81; //Equilibrium conditions hs = 0.01; is = sqrt(M*g*hs/K); // State space matrices a21 = K*is^2/M/hs^2; a23 = - 2*K*is/M/hs; a33 = - R/L; b3 = 1/L; a1 = [0 1 0; a21 0 a23; 0 0 a33]; b1 = [0; 0; b3]; c1 = [1 0 0]; d1 = 0; // Transfer functions G = syslin(''c'',a1,b1,c1,d1); Ts = 0.01; [B,A,k] = myc2d(G,Ts); //polynomials are returned [Ds,num,den] = ss2tf(G); num = clean(num); den = clean(den); // Transient specifications rise = 0.15; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi); // Setting up simulation parameters for basic.xcos st = 0.0001; // desired change in h, in m. t_init = 0; // simulation start time t_final = 0.5; // simulation end time // Setting up simulation parameters for c_ss_cl.xcos N_var = 0; xInitial = [0 0 0]; N = 1; C = 0; D = 1; [Tc1,Rc1] = cosfil_ip(Tc,Rc); // Tc/Rc [Sc2,Rc2] = cosfil_ip(Sc,Rc); // Sc/Rc [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 37 fields: save_id: gallery36 name: Ex9_1_2 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.1) Pole placement controller for magnetically suspended ball problem' save_time: 2025-05-08 12:24:27+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clss;cscope;dlr;rand_m;samphold_m;split_f;step_function;super_f;text_f;tows_c media: gallery36.png script_dump: '// Pole placement controller for magnetically suspended ball problem, discussed in Example 9.3 on page 331. // 9.1 // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.2. // 9.3 // function [goodpoly,badpoly] = polsplit2(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. // Input is a polynomial in increasing degree of z^{-1} // Optional input is a, where a <= 1. // Factor that has roots of z^{-1} outside a is called // good and the rest bad. // If a is not specified, it will be assumed as 1-1.0e-5 function [goodpoly,badpoly] = polsplit2(fac,a) if argn(2) == 1, a = 1-1.0e-5; end if a>1 error(''good polynomial is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts1 = roots(fac1); rts = rts1(length(rts1):-1:1); // extract good and bad roots badindex = find(abs(rts)>=a); // mtlb_find has been replaced by find badpoly = coeff(poly((rts(badindex)),"z","roots")); goodindex = find(abs(rts) 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // Design of 2-DOF pole placement controller, as discussed in Sec. 9.2. // 9.5 // function [Rc,Sc,Tc,gamma] = pp_basic(B,A,k,phi) // calculates pole placement controller function [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit2(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit2(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dphi = length(phi) - 1; [S1,dS1,R1,dR1] = xdync(N,dN,Ab,dAb,phi,dphi); // Determination of control law Rc = convol(Bg,R1); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Magnetically suspended ball problem // Operating conditions M = 0.05; L = 0.01; R = 1; K = 0.0001; g = 9.81; //Equilibrium conditions hs = 0.01; is = sqrt(M*g*hs/K); // State space matrices a21 = K*is^2/M/hs^2; a23 = - 2*K*is/M/hs; a33 = - R/L; b3 = 1/L; a1 = [0 1 0; a21 0 a23; 0 0 a33]; b1 = [0; 0; b3]; c1 = [1 0 0]; d1 = 0; // Transfer functions G = syslin(''c'',a1,b1,c1,d1); Ts = 0.01; [B,A,k] = myc2d(G,Ts); //polynomials are returned [Ds,num,den] = ss2tf(G); num = clean(num); den = clean(den); // Transient specifications rise = 0.15; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi); // Setting up simulation parameters for basic.xcos st = 0.0001; // desired change in h, in m. t_init = 0; // simulation start time t_final = 0.5; // simulation end time // Setting up simulation parameters for c_ss_cl.xcos N_var = 0; xInitial = [0 0 0]; N = 1; C = 0; D = 1; [Tc1,Rc1] = cosfil_ip(Tc,Rc); // Tc/Rc [Sc2,Rc2] = cosfil_ip(Sc,Rc); // Sc/Rc [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 38 fields: save_id: gallery37 name: Ex9_21_1 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.21) DC motor with PID control tuned through pole placement technique' save_time: 2025-05-30 12:29:41+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;dlr;samphold_m;split_f;step_function;super_f;text_f;tows_c media: gallery37.png script_dump: '// DC motor with PID control, tuned through pole placement technique, as in Example 9.18. // 9.21 // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Solution to Aryabhatta''s identity arising in PID controller design, namely Eq. 9.37 on page 363. // 9.20 function [Rc,Sc] = pp_pid(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity dB = length(B) - 1; dA = length(A) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(B,dB,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(A,dA,Delta,dDelta); dphi = length(phi)-1; [Sc,dSc,R,dR] = xdync(N,dN,D,dD,phi,dphi); Rc = convol(R,Delta); endfunction; // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // PD control law from polynomial coefficients, as explained in Sec. 9.8. // 9.22 function [K,taud,N] = pd(Rc,Sc,Ts) // Both Rc and Sc have to be degree one polynomials s0 = Sc(1); s1 = Sc(2); r1 = Rc(2); K = (s0+s1)/(1+r1); N = (s1-s0*r1)/r1/(s0+s1); taudbyN = -Ts*r1/(1+r1); taud = taudbyN * N; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Motor control problem // Transfer function a = [-1 0; 1 0]; b = [1; 0]; c = [0 1]; d = 0; G = syslin(''c'',a,b,c,d); Ts = 0.25; [B,A,k] = myc2d(G,Ts); [Ds,num,den] = ss2tf(G); // Transient specifications rise = 3; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design Delta = 1; //No internal model of step used [Rc,Sc] = pp_pid(B,A,k,phi,Delta); // continuous time controller [K,taud,N] = pd(Rc,Sc,Ts); numb = K*[1 taud*(1+1/N)]; denb = [1 taud/N]; numf = 1; denf = 1; // simulation parameters st = 1; // desired change in position t_init = 0; // simulation start time t_final = 20; // simulation end time t = 0.5; // sampling time st1 = 0; // continuous controller simulation: g_s_cl3.xcos num1 = 0; den1 = 1; // discrete controller simulation: g_s_cl2.xcos // u1: -0.1 to 0.8 // y1: 0 to 1.4 C = 0; D = 1; N = 1; gamm = 1; Tc = Sc; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // N/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D Numb = polyno(numb,''s''); Denb = polyno(denb,''s''); Numf = polyno(numf,''s''); Denf = polyno(denf,''s''); Num1 = polyno(num1,''s''); Den1 = polyno(den1,''s'');' - model: saveAPI.gallery pk: 39 fields: save_id: gallery38 name: Ex9_21_2 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.21) DC motor with PID control tuned through pole placement technique' save_time: 2025-05-30 12:29:41+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clr;cscope;split_f;step_function;super_f;text_f;tows_c media: gallery38.png script_dump: '// DC motor with PID control, tuned through pole placement technique, as in Example 9.18. // 9.21 // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Solution to Aryabhatta''s identity arising in PID controller design, namely Eq. 9.37 on page 363. // 9.20 function [Rc,Sc] = pp_pid(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity dB = length(B) - 1; dA = length(A) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(B,dB,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(A,dA,Delta,dDelta); dphi = length(phi)-1; [Sc,dSc,R,dR] = xdync(N,dN,D,dD,phi,dphi); Rc = convol(R,Delta); endfunction; // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // PD control law from polynomial coefficients, as explained in Sec. 9.8. // 9.22 function [K,taud,N] = pd(Rc,Sc,Ts) // Both Rc and Sc have to be degree one polynomials s0 = Sc(1); s1 = Sc(2); r1 = Rc(2); K = (s0+s1)/(1+r1); N = (s1-s0*r1)/r1/(s0+s1); taudbyN = -Ts*r1/(1+r1); taud = taudbyN * N; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // Motor control problem // Transfer function a = [-1 0; 1 0]; b = [1; 0]; c = [0 1]; d = 0; G = syslin(''c'',a,b,c,d); Ts = 0.25; [B,A,k] = myc2d(G,Ts); [Ds,num,den] = ss2tf(G); // Transient specifications rise = 3; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design Delta = 1; //No internal model of step used [Rc,Sc] = pp_pid(B,A,k,phi,Delta); // continuous time controller [K,taud,N] = pd(Rc,Sc,Ts); numb = K*[1 taud*(1+1/N)]; denb = [1 taud/N]; numf = 1; denf = 1; // simulation parameters st = 1; // desired change in position t_init = 0; // simulation start time t_final = 20; // simulation end time t = 0.5; // sampling time st1 = 0; // continuous controller simulation: g_s_cl3.xcos num1 = 0; den1 = 1; // discrete controller simulation: g_s_cl2.xcos // u1: -0.1 to 0.8 // y1: 0 to 1.4 C = 0; D = 1; N = 1; gamm = 1; Tc = Sc; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // N/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D Numb = polyno(numb,''s''); Denb = polyno(denb,''s''); Numf = polyno(numf,''s''); Denf = polyno(denf,''s''); Num1 = polyno(num1,''s''); Den1 = polyno(den1,''s'');' - model: saveAPI.gallery pk: 40 fields: save_id: gallery39 name: basic_disc description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.7) Simulation of closed loop system with an unstable controller' save_time: 2025-05-08 12:24:27+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;split_f;step_function;super_f;text_f;tows_c media: gallery39.png script_dump: '// Simulation of closed loop system with an unstable controller, as discussed in Example 9.5 on page 335. // 9.7 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.2. // 9.3 // function [goodpoly,badpoly] = polsplit2(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. // Input is a polynomial in increasing degree of z^{-1} // Optional input is a, where a <= 1. // Factor that has roots of z^{-1} outside a is called // good and the rest bad. // If a is not specified, it will be assumed as 1-1.0e-5 function [goodpoly,badpoly] = polsplit2(fac,a) if argn(2) == 1, a = 1-1.0e-5; end if a>1 error(''good polynomial is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts1 = roots(fac1); rts = rts1(length(rts1):-1:1); // extract good and bad roots badindex = find(abs(rts)>=a); // mtlb_find has been replaced by find badpoly = coeff(poly((rts(badindex)),"z","roots")); goodindex = find(abs(rts)1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Design of 2-DOF pole placement controller, as discussed in Sec. 9.2. // 9.5 // function [Rc,Sc,Tc,gamma] = pp_basic(B,A,k,phi) // calculates pole placement controller function [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit2(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit2(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dphi = length(phi) - 1; [S1,dS1,R1,dR1] = xdync(N,dN,Ab,dAb,phi,dphi); // Determination of control law Rc = convol(Bg,R1); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction Ts = 1; B = [1 -3]; A = [1 2 -8]; k = 1; // Since k=1, tf is of the form z^-1 [zk,dzk] = zpowk(k); // int1 = 0;//---- int1 // Transient specifications rise = 10; epsilon = 0.1; phi = desired(Ts,rise,epsilon); // Controller design [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi); // simulation parameters for basic_disc.xcos //While simulating for t_final = 100, set the limit of Y axis of each scope //u1: -0.2 to 3 //y1: -0.1 to 1.2 st = 1.0; // Desired change in setpoint t_init = 0; // Simulation start time t_final = 1000; // Simulation end time // Simulation parameters for stb_disc.xcos N_var = 0; C = 0; D = 1; N = 1; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D [Tcp,Rcp] = cosfil_ip(Tc,Rc); // Tc/Rc [Scp_b,Rcp_b] = cosfil_ip(Sc,Rc); // Sc/Rc' - model: saveAPI.gallery pk: 41 fields: save_id: gallery40 name: stb_disc description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.7) Simulation of closed loop system with an unstable controller' save_time: 2025-05-08 12:24:27+00:00 book: 2048 data_dump: blocks: bigsom_f;clindummy_f;clkoutv_f;clksplit_f;clock_c;cscope;dlr;ramp;rand_m;split_f;step_function;super_f;switch_f;tows_c media: gallery40.png script_dump: '// Simulation of closed loop system with an unstable controller, as discussed in Example 9.5 on page 335. // 9.7 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.2. // 9.3 // function [goodpoly,badpoly] = polsplit2(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. // Input is a polynomial in increasing degree of z^{-1} // Optional input is a, where a <= 1. // Factor that has roots of z^{-1} outside a is called // good and the rest bad. // If a is not specified, it will be assumed as 1-1.0e-5 function [goodpoly,badpoly] = polsplit2(fac,a) if argn(2) == 1, a = 1-1.0e-5; end if a>1 error(''good polynomial is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts1 = roots(fac1); rts = rts1(length(rts1):-1:1); // extract good and bad roots badindex = find(abs(rts)>=a); // mtlb_find has been replaced by find badpoly = coeff(poly((rts(badindex)),"z","roots")); goodindex = find(abs(rts)1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Design of 2-DOF pole placement controller, as discussed in Sec. 9.2. // 9.5 // function [Rc,Sc,Tc,gamma] = pp_basic(B,A,k,phi) // calculates pole placement controller function [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit2(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit2(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dphi = length(phi) - 1; [S1,dS1,R1,dR1] = xdync(N,dN,Ab,dAb,phi,dphi); // Determination of control law Rc = convol(Bg,R1); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction Ts = 1; B = [1 -3]; A = [1 2 -8]; k = 1; // Since k=1, tf is of the form z^-1 [zk,dzk] = zpowk(k); // int1 = 0;//---- int1 // Transient specifications rise = 10; epsilon = 0.1; phi = desired(Ts,rise,epsilon); // Controller design [Rc,Sc,Tc,gamm] = pp_basic(B,A,k,phi); // simulation parameters for basic_disc.xcos //While simulating for t_final = 100, set the limit of Y axis of each scope //u1: -0.2 to 3 //y1: -0.1 to 1.2 st = 1.0; // Desired change in setpoint t_init = 0; // Simulation start time t_final = 1000; // Simulation end time // Simulation parameters for stb_disc.xcos N_var = 0; C = 0; D = 1; N = 1; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Rcp1,Rcp2] = cosfil_ip(1,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Bp,Ap] = cosfil_ip(B,A); // B/A [zkp1,zkp2] = cosfil_ip(zk,1); // zk/1 [Cp,Dp] = cosfil_ip(C,D); // C/D [Tcp,Rcp] = cosfil_ip(Tc,Rc); // Tc/Rc [Scp_b,Rcp_b] = cosfil_ip(Sc,Rc); // Sc/Rc' - model: saveAPI.gallery pk: 42 fields: save_id: gallery41 name: Ex9_9 description: 'Digital Control (Author: K. M. Moudgalya), 9) Pole Placement Controllers, 9.9) Pole placement controller with internal model of a step for the magnetically suspended ball problem' save_time: 2025-05-08 12:24:27+00:00 book: 2048 data_dump: blocks: bigsom_f;clkoutv_f;clksplit_f;clock_c;clss;cscope;dlr;rand_m;samphold_m;split_f;step_function;super_f;tows_c media: gallery41.png script_dump: '// Pole placement controller, with internal model of a step, for the magnetically suspended ball problem, as discussed in Example 9.8 on page 339. // 9.9 // Calculation of desired closed loop characteristic polynomial, as discussed in Sec. 7.7. // 9.4 // function [phi,dphi] = desired(Ts,rise,epsilon) // Based on transient requirements, // calculates closed loop characteristic polynomial function [phi,dphi] = desired(Ts,rise,epsilon) Nr = rise/Ts; omega = %pi/2/Nr; rho = epsilon^(omega/%pi); phi = [1 -2*rho*cos(omega) rho^2]; dphi = length(phi)-1; endfunction; // Pole placement controller using internal model principle, as discussed in Sec. 9.4. // 9.8 // function [Rc,Sc,Tc,gamma,phit] = pp_im(B,A,k,phi,Delta) // Calculates 2-DOF pole placement controller. function [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta) // Setting up and solving Aryabhatta identity [Ag,Ab] = polsplit3(A); dAb = length(Ab) - 1; [Bg,Bb] = polsplit3(B); dBb = length(Bb) - 1; [zk,dzk] = zpowk(k); [N,dN] = polmul(Bb,dBb,zk,dzk); dDelta = length(Delta)-1; [D,dD] = polmul(Ab,dAb,Delta,dDelta); dphi = length(phi)-1; [S1,dS1,R1,dR1] = xdync(N,dN,D,dD,phi,dphi); // Determination of control law Rc = convol(Bg,convol(R1,Delta)); Sc = convol(Ag,S1); Tc = Ag; gamm = sum(phi)/sum(Bb); endfunction; // Discretization of continuous transfer function. The result is numerator and denominator in powers of z^{-1} and the delay term k. // 9.2 // function [B,A,k] = myc2d(G,Ts) // Produces numerator and denominator of discrete transfer // function in powers of z^{-1} // G is continuous transfer function; time delays are not allowed // Ts is the sampling time, all in consistent time units function [B,A,k] = myc2d(G,Ts) H = ss2tf(dscr(G,Ts)); num1 = coeff(H(''num'')); den1 = coeff(H(''den''));//------------- A = den1(length(den1):-1:1); num2 = num1(length(num1):-1:1); //flip nonzero = find(num1); first_nz = nonzero(1); B = num2(first_nz:length(num2)); //------------- k = length(den1) - length(num1); endfunction // Procedure to split a polynomial into good and bad factors, as discussed in Sec. 9.5. The factors that have roots outside unit circle or with negative real parts are defined as bad. // 9.12 // function [goodpoly,badpoly] = polsplit3(fac,a) // Splits a scalar polynomial of z^{-1} into good and bad // factors. Input is a polynomial in increasing degree of // z^{-1}. Optional input is a, where a <= 1. // Factors that have roots outside a circle of radius a or // with negative roots will be called bad and the rest // good. If a is not specified, it will be assumed as 1. function [goodpoly,badpoly] = polsplit3(fac,a) if argn(2) == 1, a = 1; end if a>1 error(''good polynomial also is unstable''); end fac1 = poly(fac(length(fac):-1:1),''z'',''coeff''); rts = roots(fac1); rts = rts(length(rts):-1:1); // extract good and bad roots badindex = mtlb_find((abs(rts)>=a-1.0e-5)|(real(rts)<-0.05)); badpoly = coeff(poly(rts(badindex),''z'')); goodindex = mtlb_find((abs(rts)=-0.05)); goodpoly = coeff(poly(rts(goodindex),''z'')); // scale by equating the largest terms [m,index] = max(abs(fac)); goodbad = convol(goodpoly,badpoly); goodbad = goodbad(length(goodbad):-1:1); factor1 = fac(index)/goodbad(index); goodpoly = goodpoly * factor1; goodpoly = goodpoly(length(goodpoly):-1:1); badpoly = badpoly(length(badpoly):-1:1); endfunction; // Evaluates z^-k. // 9.6 function [zk,dzk] = zpowk(k) zk = zeros(1,k+1); zk(1,k+1) = 1; dzk = k; endfunction // function [P,degP] = rowjoin(P1,degP1,P2,degP2) // MATLAB FUNCTION rowjoin TO SUPERPOSE TWO POLYNOMIAL // MATRICES // H. Kwakernaak, July, 1990 function [P,degP] = rowjoin(P1,degP1,P2,degP2) [rP1,cP1] = polsize(P1,degP1); [rP2,cP2] = polsize(P2,degP2); if cP1 ~= cP2 error(''rowjoin: Inconsistent numbers of columns''); end rP = rP1+rP2; cP = cP1; if degP1 >= degP2 degP = degP1; else degP = degP2; end if isempty(P1) P = P2; elseif isempty(P2) P = P1; else P = zeros(rP,(degP+1)*cP); P(1:rP1,1:(degP1+1)*cP1) = P1; P(rP1+1:rP,1:(degP2+1)*cP2) = P2; end endfunction // function [B,degB,A,degA,Y,degY,X,degX] = ... // left_prm(N,degN,D,degD,job,gap) // // does three different things according to integers that ''job'' takes // job = 1. // this is the default. It is always done for all jobs. // -1 -1 -1 // Given ND , returns coprime B and A where ND = A B // It is enough if one sends the first four input arguments // If gap is required to be sent, then one can send either 1 or a null // entry for job // job = 2. // first solve for job = 1 and then solve XA + YB = I // job = 3. // used in solving XD + YN = C // after finding coprime factorization, data are returned // // convention: the variable with prefix deg stand for degrees // of the corresponding polynomial matrices // // input: // N: right fraction numerator polynomial matrix // D: right fraction denominator polynomial matrix // N and D are not neccessarily coprime // gap: variable used to zero entries; default value is 1.0e+8 // // output // b and A are left coprime num. and den. polynomial matrices // X and Y are solutions to Aryabhatta identity, only for job = 2 function [B,degB,A,degA,Y,degY,X,degX] = left_prm(N,degN,D,degD,job,gap) if argn(2) == 4 | argn(2) == 5 gap = 1.0e8 ; end // pause if argn(2) == 4, job = 1; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); // Fbcols = block columns Fcols = Fbcols * (degF+1) ; // actual columns of F T1 = [];pr =[];degT1 = 0; T1rows = 0;shft = 0; S=F; sel = ones(Frows,1); T1bcols =1; abar = (Fbcols + 1):Frows; // a_super_bar of B-C.Chang while isempty(T1) | T1rows < Frows - Fbcols Srows = Frows*T1bcols; // max actual columns of result [T1,T1rows,sel,pr] = ... t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap); [T1rows,T1cols] = size(T1); if T1rows < Frows - Fbcols T1 = [T1 zeros(T1rows,Frows)]; T1bcols = T1bcols + 1; // max. block columns of result degT1 = degT1 + 1; // degree of result shft = shft +Fbcols; S = seshft(S,F,shft); sel = [sel;sel(Srows-Frows+1:Srows)]; rowvec = (T1bcols-1)*Frows+(Fbcols+1):T1bcols * Frows; abar = [abar rowvec]; // A_super_bar of B-C.chang end end [B,degB,A,degA] = colsplit(T1,degT1,Fbcols,Frows-Fbcols); [B,degB] = clcoef(B,degB); B = -B; [A,degA] = clcoef(A,degA); // pause if job == 2 S = S(mtlb_logical(sel),:); // columns [redSrows,Scols] = size(S); C = [eye(Fbcols,Fbcols) zeros(Fbcols,Scols-Fbcols)]; // append with zeros T2 = C/S; T2 = makezero(T2,gap); T2 = move_sci(T2,find(sel),Srows); [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows - Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); elseif job == 3 Y = S; degY = sel; X = degT1; degX = Fbcols; else if job ~= 1 error(''Message from left_prm:no legal job number specified'') end end endfunction // function [T1,T1rows,sel,pr] = ... // t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) // calculates the coefficient matrix T1 // redundant row information is kept in sel: redundant rows are marked // with zeros. The undeleted rows are marked with ones. function [T1,T1rows,sel,pr] = t1calc(S,Srows,T1,T1rows,sel,pr,Frows,Fbcols,abar,gap) b = 1; // vector of primary red.rows while (T1rows < Frows - Fbcols) & or(sel==1) & ~isempty(b) S = clean(S); b = indep(S(mtlb_logical(sel),:),gap); // send selected rows of S if ~isempty(b) b = clean(b); b = move_sci(b,find(sel),Srows); j = length(b); while ~(b(j) & or(abar==j)) // pick largest nonzero entry j = j-1; // of coeff. belonging to abar if ~j fprintf(''\nMessage from t1calc, called from left_prm\n\n'') error(''Denominator is noninvertible'') end end if ~or(j gap) ind = 0; else ind = 1; i = i+1; end end end if ind b =[]; else c = S(i,:)/S(1:i-1,:); c = makezero(c,gap); b = [-c 1]; end endfunction // function b = cindep( S,gap) // Used in XD + YN = C. All rows except the last of are assumed to // be independent. The aim is to check if the last row is dependent on the // rest and if so how. The coefficients of dependence are sent in b. function b = cindep( S,gap) if argn(2) == 1 gap = 1.0e8; end eps = 2.2204e-016; [rows,cols] = size(S); if rows > cols ind = 0; else sigma = svd(S); len = length(sigma); if (sigma(len)/sigma(1) <= (eps*max(i,cols))) ind = 0; //not independent else if or(sigma(1:len-1) ./sigma(2:len)>=gap) ind = 0; // not dependent else ind = 1; //independent end end end if ind b = []; else b = S(rows,:)/S(1:rows-1,:); b = makezero(b,gap); end endfunction // function C = seshft(A,B,N) //given A and B matrices, returns C = [<-A-> 0 // 0 <-B->] with B shifted east by N cols function C = seshft(A,B,N) [Arows,Acols] = size(A); [Brows,Bcols] = size(B); if N >= 0 B = [zeros(Brows,N) B]; Bcols = Bcols + N; elseif N < 0 A = [zeros(Arows,abs(N)) A]; Acols = Acols +abs(N); end if Acols < Bcols A = [A zeros(Arows,Bcols-Acols)]; elseif Acols > Bcols B = [B zeros(Brows,Acols-Bcols)]; end C = [A B]; endfunction // function B = makezero(B,gap) // where B is a vector and gap acts as a tolerance function B = makezero(B,gap) if argn(2) == 1 gap = 1.0e8; end temp = B(find(B)); // non zero entries of B temp = -gsort(-abs(temp),''g'',''d''); // absolute values sorted in descending order len = length(temp); ratio = temp(1:len-1) ./temp(2:len); // each ratio >1 min_ind = min(find(ratio>gap)); if ~isempty(min_ind) our_eps = temp(min_ind+1); zeroind = find(abs(B)<=our_eps); B(zeroind) = zeros(1,length(zeroind)); end endfunction // function result = move_sci(b,nonred,max_sci) // Moves matrix b to matrix result with the information on where to move, // decided by the indices of nonred. // The matrix result will have as many rows as b has and max number of columns. // b is augumented with zeros to have nonred number of columns; // The columns of b put into those of result as decided by nonred. function result = move_sci(b,nonred,max_sci) [brows,bcols] = size(b); b = [b zeros(brows,length(nonred)-bcols)]; result = zeros(brows,max_sci); result(:,nonred'') = b; endfunction // colsplit // The command // [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) // produces two polynomial matrix P1 and P2. P1 consists of the first // p1 columns of P and P2 consists of the remaining p2 columns of P. // H. Kwakernaak, July, 1990 function [P1,degP1,P2,degP2] = colsplit(P,degP,p1,p2) if isempty(P) P1 = []; P2 = []; degP1 = 0; degP2 = 0; return; end [rP,cP] = polsize(P,degP); if p1 < 0 | p1 > cP | p2 < 0 | p2 > cP | p1+p2 ~= cP error(''colsplit: Inconsistent numbers of columns''); end rP1 = rP; rP2 = rP; cP1 = p1; cP2 = p2; degP1= degP; degP2 = degP; if p1 == 0 P1 == []; P2 = P; elseif p2 == 0 P1 = P; P2 = []; else P1 = zeros(rP1,(degP1+1)*cP1); P2 = zeros(rP2,(degP2+1)*cP2); for i = 1:degP+1 P1(:,(i-1)*cP1+1:i*cP1) = P(:,(i-1)*cP+1:(i-1)*cP+cP1); P2(:,(i-1)*cP2+1:i*cP2) = P(:,(i-1)*cP+cP1+1:i*cP); end end endfunction; // H. Kwakernaak, July, 1990 // Modified by Kannan Moudgalya in Nov. 1992 function [P,degP] = clcoef(Q,degQ) [rQ,cQ] = polsize(Q,degQ); if and(and(Q==0)) P = zeros(rQ,cQ); degP = 0; else P = Q; degP = degQ; rP = rQ; cP = cQ; j = degP+1; while j >= 0 X = P(:,(j-1)*cP+1:j*cP) if max(sum(abs(X''))) < (1e-8)*max(sum(abs(P))) P = P(:,1:(j-1)*cP); degP = degP-1; else j = 0; end j = j-1; end end endfunction // polmul // The command // [C,degA] = polmul(A,degA,B,degB) // produces the polynomial matrix C that equals the product A*B of the // polynomial matrices A and B. // // H. Kwakernaak, July, 1990 function [C,degC] = polmul(A,degA,B,degB) [rA,cA] = polsize(A,degA); [rB,cB] = polsize(B,degB); if cA ~= rB error(''polmul: Inconsistent dimensions of input matrices''); end degC = degA+degB; C = []; for k = 0:degA+degB mi = 0; if k-degB > mi mi = k-degB; end ma = degA; if k < ma ma = k; end Ck = zeros(rA,cB); for i = mi:ma Ck = Ck + A(:,i*cA+1:(i+1)*cA)*B(:,(k-i)*cB+1:(k-i+1)*cB); end C = [C Ck]; end endfunction // function [rQ,cQ] = polsize(Q,degQ) // FUNCTION polsize TO DETERMINE THE DIMENSIONS // OF A POLYNOMIAL MATRIX // // H. Kwakernaak, August, 1990 function [rQ,cQ] = polsize(Q,degQ) [rQ,cQ] = size(Q); cQ = cQ/(degQ+1); if abs(round(cQ)-cQ) > 1e-6 error(''polsize: Degree of input inconsistent with number of columns''); else cQ = round(cQ); end endfunction // function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) // given coefficient matrix in T1, primary redundant row information sel, // solves XD + YN = C // calling order changed on 16 April 2005. Old order: // function [B,degB,A,degA,Y,degY,X,degX] = xdync(N,degN,D,degD,C,degC,gap) function [Y,degY,X,degX,B,degB,A,degA] = xdync(N,degN,D,degD,C,degC,gap) if argn(2) == 6 gap = 1.0e+8; end [F,degF] = rowjoin(D,degD,N,degN); [Frows,Fbcols] = polsize(F,degF); //Fbcols = block columns [B,degB,A,degA,S,sel,degT1,Fbcols] = left_prm(N,degN,D,degD,3,gap); //if issoln(D,degD,C,degC,B,degB,A,degA) [Crows,Ccols] = size(C); [Srows,Scols] = size(S); S = clean(S); S = S(mtlb_logical(sel),:); T2 =[]; for i = 1:Crows, Saug = seshft(S,C(i,:),0); b = cindep(Saug); b = move_sci(b,find(sel),Srows); T2 =[T2; b]; end [X,degX,Y,degY] = colsplit(T2,degT1,Fbcols,Frows-Fbcols); [X,degX] = clcoef(X,degX); [Y,degY] = clcoef(Y,degY); Y = clean(Y); X = clean(X); endfunction // Input arguments are co efficients of numerator and denominator // polynomials in ascending powers of z^-1 // Scicos/Xcos blocks need input polynomials // with positive powers of z function [nume,deno] = cosfil_ip(num,den) [Nn,Nd] = polyno(num,''z''); [Dn,Dd] = polyno(den,''z''); nume = Nn*Dd; deno = Nd*Dn; endfunction; // Updated(1-8-07) // Operations: // Polynomial definition // Flipping of coefficients // Variables ------- passed as input argument (either ''s'' or ''z'') // Both num and den are used mostly used in scicos files, // to get rid of negative powers of z // Polynomials with powers of s need to // be flipped only function [polynu,polyde] = polyno(zc,a) zc = clean(zc); polynu = poly(zc(length(zc):-1:1),a,''coeff''); if a == ''z'' polyde = %z^(length(zc) - 1); else polyde = 1; end // Scicos(4.1) Filter block shouldn''t have constant/constant if type(polynu)==1 & type(polyde)==1 if a == ''z'' polynu = %z; polyde = %z; else polynu = %s; polyde = %s; end; end; endfunction // Operating conditions M = 0.05; L = 0.01; R = 1; K = 0.0001; g = 9.81; // Equilibrium conditions hs = 0.01; is = sqrt(M*g*hs/K); // State space matrices a21 = K*is^2/M/hs^2; a23 = - 2*K*is/M/hs; a33 = - R/L; b3 = 1/L; a1 = [0 1 0; a21 0 a23; 0 0 a33]; b1 = [0; 0; b3]; c1 = [1 0 0]; d1 = 0; // Transfer functions G = syslin(''c'',a1,b1,c1,d1); Ts = 0.01; [B,A,k] = myc2d(G,Ts); // Transient specifications rise = 0.1; epsilon = 0.05; phi = desired(Ts,rise,epsilon); // Controller design Delta = [1 -1]; //internal model of step used [Rc,Sc,Tc,gamm] = pp_im(B,A,k,phi,Delta); // simulation parameters for c_ss_cl.xcos st = 0.0001; //desired change in h, in m. t_init = 0; // simulation start time t_final = 0.5; //simulation end time xInitial = [0 0 0]; N = 1; C = 0; D = 1; N_var = 0; [Tcp1,Tcp2] = cosfil_ip(Tc,1); // Tc/1 [Np,Rcp] = cosfil_ip(N,Rc); // 1/Rc [Scp1,Scp2] = cosfil_ip(Sc,1); // Sc/1 [Cp,Dp] = cosfil_ip(C,D); // C/D' - model: saveAPI.gallery pk: 43 fields: save_id: gallery42 name: ex10_10 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.10) Superposition Source Transformations and Thevenin theorem' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: capacitor;ccs;clock_c;cscope;gensin_f;ground;inductor;resistor;split_f;text_f;voltagesensor media: gallery42.png script_dump: '' - model: saveAPI.gallery pk: 44 fields: save_id: gallery43 name: ex10_11 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.11) Superposition Source Transformations and Thevenin theorem' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: bigsom_f;capacitor;ccs;clock_c;cscope;currentsensor;gainblk_f;gensin_f;ground;mux;powblk_f;resistor;split_f media: gallery43.png script_dump: '' - model: saveAPI.gallery pk: 45 fields: save_id: gallery44 name: ex10_1 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.1) Forced Response to sinusoidal functions' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cscope;currentsensor;ground;inductor;mux;resistor;sinevoltage;split_f;voltagesensor media: gallery44.png script_dump: '' - model: saveAPI.gallery pk: 46 fields: save_id: gallery45 name: ex10_6 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.6) Impedance' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;ground;impsplit_f;inductor;resistor;sinevoltage;split_f media: gallery45.png script_dump: '' - model: saveAPI.gallery pk: 47 fields: save_id: gallery46 name: ex10_7 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.7) Nodal and Mesh analysis' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: capacitor;ccs;clock_c;cscope;gensin_f;ground;inductor;mux;potentialsensor;resistor;split_f;text_f media: gallery46.png script_dump: '' - model: saveAPI.gallery pk: 48 fields: save_id: gallery47 name: ex10_8 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.8) Nodal and Mesh analysis' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;cvs;delay_f;gainblk_f;ground;mux;resistor;sinevoltage;split_f media: gallery47.png script_dump: '' - model: saveAPI.gallery pk: 49 fields: save_id: gallery48 name: ex10_9 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 10) Sinusoidal Steady state Analysis, 10.9) Superposition Source Transformations and Thevenin theorem' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: bigsom_f;capacitor;ccs;clock_c;cscope;gensin_f;ground;impsplit_f;inductor;potentialsensor;resistor;split_f;text_f media: gallery48.png script_dump: '' - model: saveAPI.gallery pk: 50 fields: save_id: gallery49 name: ex12_1 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 12) Polyphase Circuits, 12.1) Single phase three wire systems' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cscope;currentsensor;cvs;gensin_f;ground;inductor;mux;resistor;split_f media: gallery49.png script_dump: '' - model: saveAPI.gallery pk: 51 fields: save_id: gallery50 name: ex13_7 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 13) Magnetically coupled circuits, 13.7) The Ideal Transformer' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;gainblk_f;ground;idealtransformer;impsplit_f;powblk_f;resistor media: gallery50.png script_dump: '' - model: saveAPI.gallery pk: 52 fields: save_id: gallery51 name: ex17_4 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 17) Two Port Networks, 17.4) Admittance parameters' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;mux;resistor;split_f;text_f media: gallery51.png script_dump: '' - model: saveAPI.gallery pk: 53 fields: save_id: gallery52 name: ex18_2 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 18) Fourier Circuit Analysis, 18.2) Complete Response to periodic Forcing Functions' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cscope;currentsensor;cvs;diode;gensqr_f;ground;impsplit_f;inductor;potentialsensor;resistor;text_f media: gallery52.png script_dump: '' - model: saveAPI.gallery pk: 54 fields: save_id: gallery53 name: ex18_8 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 18) Fourier Circuit Analysis, 18.8) The physical significance of system function' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cscope;cvs;gainblk_f;ground;impsplit_f;inductor;potentialsensor;resistor;time_f media: gallery53.png script_dump: '' - model: saveAPI.gallery pk: 55 fields: save_id: gallery54 name: ex3_11 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.11) Resistors in series and parallel' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;impsplit_f;resistor media: gallery54.png script_dump: '' - model: saveAPI.gallery pk: 56 fields: save_id: gallery55 name: ex3_13 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.13) Voltage and Current division' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cscope;ground;impsplit_f;resistor;sinevoltage;voltagesensor media: gallery55.png script_dump: '' - model: saveAPI.gallery pk: 57 fields: save_id: gallery56 name: ex3_14 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.14) Voltage and Current division' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cscope;currentsensor;ground;impsplit_f;resistor;sinevoltage media: gallery56.png script_dump: '' - model: saveAPI.gallery pk: 58 fields: save_id: gallery57 name: ex3_1 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.1) Kirchoff current law' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;const_m;cscope;currentsensor;ground;split_f;text_f media: gallery57.png script_dump: '' - model: saveAPI.gallery pk: 59 fields: save_id: gallery58 name: ex3_2 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.2) Kirchoff voltage law' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cmscope;constantvoltage;currentsensor;ground;potentialsensor;resistor;split_f media: gallery58.png script_dump: '' - model: saveAPI.gallery pk: 60 fields: save_id: gallery59 name: ex3_3 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.3) Kirchoff voltage law' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;cmscope;constantvoltage;ground;split_f;voltagesensor media: gallery59.png script_dump: '' - model: saveAPI.gallery pk: 61 fields: save_id: gallery60 name: ex3_4 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.4) Kirchoff voltage law' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;constantvoltage;const_m;cscope;ground;potentialsensor;resistor;split_f media: gallery60.png script_dump: '' - model: saveAPI.gallery pk: 62 fields: save_id: gallery61 name: ex3_5 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.5) The Single Loop Circuit' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;cvs;gainblk_f;ground;mux;powblk_f;prod_f;resistor;split_f;text_f;voltagesensor media: gallery61.png script_dump: '' - model: saveAPI.gallery pk: 63 fields: save_id: gallery62 name: ex3_6 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.6) The single node pair circuit' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;const_m;cscope;gainblk_f;ground;mux;potentialsensor;powblk_f;resistor;split_f media: gallery62.png script_dump: '' - model: saveAPI.gallery pk: 64 fields: save_id: gallery63 name: ex3_9 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 3) Voltage and Current laws, 3.9) Series and Parallel connected sources' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;impsplit_f;resistor media: gallery63.png script_dump: '' - model: saveAPI.gallery pk: 65 fields: save_id: gallery64 name: ex4_10 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.10) Mesh analysis' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;cvs;gainblk_f;ground;resistor;split_f;text_f;voltagesensor media: gallery64.png script_dump: '' - model: saveAPI.gallery pk: 66 fields: save_id: gallery65 name: ex4_11 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.11) The Supermesh' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;ground;mux;resistor;split_f;text_f media: gallery65.png script_dump: '' - model: saveAPI.gallery pk: 67 fields: save_id: gallery66 name: ex4_12 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.12) The Supermesh' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;const_m;cscope;currentsensor;delay_f;gainblk_f;ground;mux;resistor;split_f;voltagesensor media: gallery66.png script_dump: '' - model: saveAPI.gallery pk: 68 fields: save_id: gallery67 name: ex4_1 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.1) Nodal analysis' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;const_m;cscope;currentsensor;ground;resistor;split_f;text_f media: gallery67.png script_dump: '' - model: saveAPI.gallery pk: 69 fields: save_id: gallery68 name: ex4_2 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.2) Nodal analysis' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;cmscope;const_m;cscope;ground;potentialsensor;resistor;split_f;text_f;voltagesensor media: gallery68.png script_dump: '' - model: saveAPI.gallery pk: 70 fields: save_id: gallery69 name: ex4_5 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.5) The supernode' save_time: 2025-05-08 12:24:27+00:00 book: 215 data_dump: blocks: ccs;clock_c;constantvoltage;const_m;cscope;ground;potentialsensor;resistor;split_f;text_f media: gallery69.png script_dump: '' - model: saveAPI.gallery pk: 71 fields: save_id: gallery70 name: ex4_6 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.6) The supernode' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: ccs;clock_c;constantvoltage;const_m;cscope;cvs;delay_f;gainblk_f;ground;mux;potentialsensor;resistor;split_f;text_f;voltagesensor media: gallery70.png script_dump: '' - model: saveAPI.gallery pk: 72 fields: save_id: gallery71 name: ex4_7 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.7) Mesh analysis' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;prod_f;resistor;split_f;text_f;voltagesensor media: gallery71.png script_dump: '' - model: saveAPI.gallery pk: 73 fields: save_id: gallery72 name: ex4_8 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.8) Mesh analysis' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;cmscope;constantvoltage;cscope;currentsensor;ground;resistor;split_f;text_f media: gallery72.png script_dump: '' - model: saveAPI.gallery pk: 74 fields: save_id: gallery73 name: ex4_9 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 4) Basic Nodal and Mesh Analysis, 4.9) Mesh analysis' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;cvs;gainblk_f;ground;resistor;split_f;text_f media: gallery73.png script_dump: '' - model: saveAPI.gallery pk: 75 fields: save_id: gallery74 name: ex6_11 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.11) Thevenin and Norton Equivalent circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;ground;potentialsensor;resistor;split_f media: gallery74.png script_dump: '' - model: saveAPI.gallery pk: 76 fields: save_id: gallery75 name: ex6_13 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.13) Thevenin and Norton Equivalent circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: ccs;clock_c;cmscope;constantvoltage;const_m;currentsensor;ground;potentialsensor;resistor;split_f media: gallery75.png script_dump: '' - model: saveAPI.gallery pk: 77 fields: save_id: gallery76 name: ex6_14 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.14) Thevenin and Norton Equivalent circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: ccs;clock_c;constantvoltage;cscope;delay_f;gainblk_f;ground;potentialsensor;resistor;split_f media: gallery76.png script_dump: '' - model: saveAPI.gallery pk: 78 fields: save_id: gallery77 name: ex6_15 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.15) Thevenin and Norton Equivalent circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;const_m;cscope;cvs;ground;resistor;split_f;voltagesensor media: gallery77.png script_dump: '' - model: saveAPI.gallery pk: 79 fields: save_id: gallery78 name: ex6_16 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.16) Maximum power transfer' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: ccs;clock_c;cscope;delay_f;gainblk_f;ground;powblk_f;resistor;sinevoltage;split_f;text_f;voltagesensor media: gallery78.png script_dump: '' - model: saveAPI.gallery pk: 80 fields: save_id: gallery79 name: ex6_1 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.1) The Superposition principle' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: bigsom_f;ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;ground;resistor;split_f media: gallery79.png script_dump: '' - model: saveAPI.gallery pk: 81 fields: save_id: gallery80 name: ex6_20 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.20) Compensation Theorem' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;cscope;currentsensor;ground;inductor;resistor;sinevoltage;split_f;summation media: gallery80.png script_dump: '' - model: saveAPI.gallery pk: 82 fields: save_id: gallery81 name: ex6_21 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.21) Compensation Theorem' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f;summation media: gallery81.png script_dump: '' - model: saveAPI.gallery pk: 83 fields: save_id: gallery82 name: ex6_23 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.23) Source Transformations' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f media: gallery82.png script_dump: '' - model: saveAPI.gallery pk: 84 fields: save_id: gallery83 name: ex6_24 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.24) Source Transformations' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: ccs;clock_c;constantvoltage;cscope;currentsensor;delay_f;ground;resistor;split_f;voltagesensor media: gallery83.png script_dump: '' - model: saveAPI.gallery pk: 85 fields: save_id: gallery84 name: ex6_3 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.3) The Superposition principle' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: bigsom_f;ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;cvs;gainblk_f;ground;resistor;split_f media: gallery84.png script_dump: '' - model: saveAPI.gallery pk: 86 fields: save_id: gallery85 name: ex6_4 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.4) The Superposition principle' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: bigsom_f;ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;ground;resistor;split_f media: gallery85.png script_dump: '' - model: saveAPI.gallery pk: 87 fields: save_id: gallery86 name: ex6_5 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.5) The Superposition principle' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: bigsom_f;clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f media: gallery86.png script_dump: '' - model: saveAPI.gallery pk: 88 fields: save_id: gallery87 name: ex6_6 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.6) The Superposition principle' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: bigsom_f;ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;cvs;gainblk_f;ground;resistor;split_f media: gallery87.png script_dump: '' - model: saveAPI.gallery pk: 89 fields: save_id: gallery88 name: ex6_8 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 6) Network Theorems and useful Circuit Analysis Techniques, 6.8) The Superposition principle' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: bigsom_f;ccs;clock_c;constantvoltage;const_m;cscope;currentsensor;cvs;gainblk_f;ground;resistor;split_f media: gallery88.png script_dump: '' - model: saveAPI.gallery pk: 90 fields: save_id: gallery89 name: ex7_11 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 7) Capacitors and Inductors, 7.11) Modeling Capacitors and Inductors' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;clock_c;cscope;ground;opamp;resistor;sinevoltage;split_f;voltagesensor media: gallery89.png script_dump: '' - model: saveAPI.gallery pk: 91 fields: save_id: gallery90 name: ex8_10 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.10) Driven RC circuits' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;clock_c;constantvoltage;cscope;currentsensor;ground;mux;resistor;split_f;voltagesensor media: gallery90.png script_dump: '' - model: saveAPI.gallery pk: 92 fields: save_id: gallery91 name: ex8_11 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.11) Driven RC circuits' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;ccs;clock_c;cscope;expression;ground;potentialsensor;resistor;split_f;time_f media: gallery91.png script_dump: '' - model: saveAPI.gallery pk: 93 fields: save_id: gallery92 name: ex8_1 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.1) The Source free RL Circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;cscope;gainblk_f;integral_m;split_f;step_function;summation media: gallery92.png script_dump: '' - model: saveAPI.gallery pk: 94 fields: save_id: gallery93 name: ex8_2 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.2) The Source free RL Circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;cscope;gainblk_f;integral_m;split_f;step_function;summation media: gallery93.png script_dump: '' - model: saveAPI.gallery pk: 95 fields: save_id: gallery94 name: ex8_3 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.3) The Source free RC Circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;clock_c;cscope;ground;resistor;split_f;voltagesensor media: gallery94.png script_dump: '' - model: saveAPI.gallery pk: 96 fields: save_id: gallery95 name: ex8_4 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.4) A more General Perspective' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;cscope;gainblk_f;integral_m;mux;split_f;step_function;summation;text_f media: gallery95.png script_dump: '' - model: saveAPI.gallery pk: 97 fields: save_id: gallery96 name: ex8_8 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 8) Basic RL and RC circuits, 8.8) Natural and Forced Response' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;gainblk_f;ground;integral_m;mux;resistor;split_f;step_function;summation;text_f media: gallery96.png script_dump: '' - model: saveAPI.gallery pk: 98 fields: save_id: gallery97 name: ex9_2 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 9) The RLC Circuit, 9.2) The Overdamped parallel circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;clock_c;cscope;ground;inductor;potentialsensor;resistor;split_f media: gallery97.png script_dump: '' - model: saveAPI.gallery pk: 99 fields: save_id: gallery98 name: ex9_3 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 9) The RLC Circuit, 9.3) The Overdamped parallel circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;clock_c;constantvoltage;cscope;currentsensor;gainblk_f;ground;inductor;mux;potentialsensor;resistor;split_f media: gallery98.png script_dump: '' - model: saveAPI.gallery pk: 100 fields: save_id: gallery99 name: ex9_6 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 9) The RLC Circuit, 9.6) The Underdamped parallel RLC circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: clock_c;cscope;gainblk_f;integral_m;split_f;summation media: gallery99.png script_dump: '' - model: saveAPI.gallery pk: 101 fields: save_id: gallery100 name: ex9_7 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 9) The RLC Circuit, 9.7) The Source free series RLC Circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;ccs;clock_c;const_m;cscope;currentsensor;ground;inductor;resistor;split_f media: gallery100.png script_dump: '' - model: saveAPI.gallery pk: 102 fields: save_id: gallery101 name: ex9_8 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 9) The RLC Circuit, 9.8) The Source free series RLC Circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;cvs;delay_f;gainblk_f;ground;inductor;resistor;split_f;voltagesensor media: gallery101.png script_dump: '' - model: saveAPI.gallery pk: 103 fields: save_id: gallery102 name: ex9_9 description: 'Engineering Circuit Analysis (Author: W. Hayt, J. Kemmerly And S. Durbin), 9) The RLC Circuit, 9.9) The Complete response of RLC circuit' save_time: 2025-05-08 12:24:28+00:00 book: 215 data_dump: blocks: ccs;clock_c;const_m;cscope;currentsensor;ground;mux;potentialsensor;resistor;split_f;voltagesensor media: gallery102.png script_dump: '' - model: saveAPI.gallery pk: 104 fields: save_id: gallery103 name: Ex6_23 description: 'Electrical Machines (Author: R. K. Srivastava), 6) Synchronous Machines, 6.23) To find maximum value of power angle and maximum value of overshoot' save_time: 2025-05-08 12:24:28+00:00 book: 2777 data_dump: blocks: clock_c;clr;const;cscope;endblk media: gallery103.png script_dump: ' // ELECTRICAL MACHINES // R.K.Srivastava // First Impression 2011 // CENGAGE LEARNING INDIA PVT. LTD // CHAPTER : 6 : SYNCHRONOUS MACHINES // EXAMPLE : 6.23 // GIVEN DATA p = 4; // Number of the poles in the Alternator f = 50; // Frequency in Hertz pkw = 500; // Alternator delivering load in kilo-watts pkwinc = 1000; // Generator increases its share of the common elictrical in kilo-watts Kj = 1.5; // Inertia acceleration coefficient for the combined prime mover-alternator in N-m/elec deg/second square Kd = 12; // Damping torque coefficient in N-m/elec deg/second delta1 = 9; // Initial value of the Power angle in degree // CALCULATIONS delta2 = (pkwinc/pkw)*delta1; // Final value (maximum value) of the Power angle in degree (considering Linear variation) ws = (4*%pi*f)/p; // Rotational speed in Radians per second Ts = (pkw*1000)/ws; // Synchornizing torque at 500kW in N-m Ks = Ts/delta1; // Synchornizing torque cofficient at 500kW in N-m/elec-deg // Laplace transform of the swing Equation can be written as :- s^2 + ((Kd/Kj)*s) + (Ks/Kj) = 0, s^2 + (12/1.5)s + (353.86/1.5) = 0 and compring with the standard equation s^2 + s(2*zeta*Wn) + Wn^2 = 0 we get:- mentined below (refer page no. 454 and 455) Wn = sqrt(Ks/Kj); // Natural frequency of oscillations in Radians per second fn = Wn/(2*%pi); // Frequency of natural oscillations in Hertz zeta = (1*Kd)/(2*Wn*Kj); // Damping ratio Wd = Wn*(sqrt(1-zeta^2)); // Frequency of damped oscillations in radians/s fd = Wd/(2*%pi); // Frequency of damped oscillations in Hertz ts = 5/(zeta*Wn); // Settling time in second deltamax = delta1 + 1.42*(delta2-delta1); // The maximum overshoot for damping ratio of 0.2604 is about 42% the maximum appoximate value of the overshoot in terms of 1% tolearance band in Electrical degree // DISPLAY RESULTS disp("EXAMPLE : 6.23: SOLUTION :-"); printf("\n (a.1) Final value (maximum value) of the Power angle (considering Linear variation), delta2 = %.f degree \n",delta2) printf("\n (a.2) Natural frequency of oscillations, Ns = %.2f radians/s \n",Wn) printf("\n (a.3) Damping ratio, zeta = %.4f \n",zeta) printf("\n (a.4) Frequency of damped oscillations, Wd = %.2f radians/s \n",Wd) printf("\n (a.5) Settling time, ts = %.2f seconds \n",ts) printf("\n (b) The maximum overshoot for damping ratio of 0.2604 is about 42 percent the maximum appoximate value of the overshoot in terms of 1 percent tolearance band is, deltamax = %.2f degree \n",deltamax) printf("\n\n FOR CASE (C) CANNOT BE DO IT IN THIS BECAUSE AS IT REQUIRES MATLAB SIMULINK \n")' - model: saveAPI.gallery pk: 105 fields: save_id: gallery104 name: eg12_2 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 12) Simplifying logical functions, 12.2) Prove the given theoram' save_time: 2025-05-08 12:24:28+00:00 book: 293 data_dump: '' blocks: clock_c;cmscope;convert;gensqr_f;in_f;logic;out_f;split_f;super_f;text_f media: gallery104.png script_dump: '' - model: saveAPI.gallery pk: 106 fields: save_id: gallery105 name: eg12_3a description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 12) Simplifying logical functions, 12.3.a) Design a digital logic circuit that provides logic 1 whenever majority votes yes' save_time: 2025-05-08 12:24:28+00:00 book: 293 data_dump: blocks: clock_c;cmscope;convert;gensqr_f;in_f;logic;out_f;split_f;super_f;text_f media: gallery105.png script_dump: '' - model: saveAPI.gallery pk: 107 fields: save_id: gallery106 name: eg12_3b description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 12) Simplifying logical functions, 12.3.b) Modify part A so that only NAND gates are used' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;cmscope;convert;gensqr_f;in_f;logic;out_f;split_f;super_f;text_f media: gallery106.png script_dump: '' - model: saveAPI.gallery pk: 108 fields: save_id: gallery107 name: eg2_10 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 2) The circuit elements, 2.10) Design an opamp circuit solution of the given equation' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;cscope;ground;impsplit_f;inimpl_f;opamp;outimpl_f;resistor;split_f;super_f;text_f;voltagesensor media: gallery107.png script_dump: '' - model: saveAPI.gallery pk: 109 fields: save_id: gallery108 name: eg3_10 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.10) Find the value of the node pair voltages V1 and V2' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;cmscope;constantvoltage;ground;resistor;split_f;text_f;voltagesensor media: gallery108.png script_dump: '' - model: saveAPI.gallery pk: 110 fields: save_id: gallery109 name: eg3_11 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.11) Find the branch current flowing through R2' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: '' blocks: clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f;text_f media: gallery109.png script_dump: '' - model: saveAPI.gallery pk: 111 fields: save_id: gallery110 name: eg3_14 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.14) Find the value of the output voltage' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;cscope;ground;resistor;split_f;text_f;voltagesensor media: gallery110.png script_dump: '' - model: saveAPI.gallery pk: 112 fields: save_id: gallery111 name: eg3_15 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.15) Find the current delivered to the source by the network' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f;text_f media: gallery111.png script_dump: '' - model: saveAPI.gallery pk: 113 fields: save_id: gallery112 name: eg3_5 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.5) Determine the current which flows through R2' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f;text_f media: gallery112.png script_dump: '' - model: saveAPI.gallery pk: 114 fields: save_id: gallery113 name: eg3_6 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.6) Find the power dissipation in R1' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;const_m;cscope;currentsensor;ground;powblk_f;prod_f;resistor;split_f;text_f media: gallery113.png script_dump: '' - model: saveAPI.gallery pk: 115 fields: save_id: gallery114 name: eg3_7 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.7) Find the current which flows through R2' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;resistor;split_f;sum_f;text_f media: gallery114.png script_dump: '' - model: saveAPI.gallery pk: 116 fields: save_id: gallery115 name: eg3_9 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 3) Elementary network theory, 3.9) Find the magnitude and direction of each of the branch currents' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;cmscope;constantvoltage;currentsensor;ground;resistor;split_f;text_f media: gallery115.png script_dump: '' - model: saveAPI.gallery pk: 117 fields: save_id: gallery116 name: eg5_1 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.1) Find the expression for the current flowing through the circuit' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: clock_c;constantvoltage;cscope;currentsensor;ground;inductor;resistor;split_f;step_function;switch;text_f media: gallery116.png script_dump: '' - model: saveAPI.gallery pk: 118 fields: save_id: gallery117 name: eg5_2 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.2) Find the expression for the current flowing through the circuit and the total energy dissipated in the resistor' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: capacitor;clock_c;cscope;currentsensor;ground;resistor;split_f;step_function;switch;text_f media: gallery117.png script_dump: 'C = 10*10^-6 ; //capacitance(in farads) R = 0.2*10^6; //resistance (in ohms) Vi = 40; //initial voltage of the capacitor (in volts) Wc = (1/2)*C*Vi^2; //energy stored in the capacitor //current flowing in circuit as a function of time i(t) = 2*10^-4*exp(-t/2) //power dissipated in the resistor = R*i^2 Wr = integrate(''R*4*10^-8*exp(-t)'',''t'',0,100) disp(Wc,"energy stored in the capacitor(in Joules) = ") disp(Wr,"energy dissipated in the resistor(in Joules) = ")' - model: saveAPI.gallery pk: 119 fields: save_id: gallery118 name: eg5_3 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.3) Determine the voltage which appears across each capacitor at steady state' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: capacitor;clock_c;cmscope;ground;resistor;split_f;step_function;switch;text_f;voltagesensor media: gallery118.png script_dump: '' - model: saveAPI.gallery pk: 120 fields: save_id: gallery119 name: eg5_5 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.5) Find the complete solution for the charge on the capacitor and show a plot of the response' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: capacitor;clock_c;cmscope;constantvoltage;const_m;ground;inductor;prod_f;resistor;split_f;step_function;switch;text_f;voltagesensor media: gallery119.png script_dump: '' - model: saveAPI.gallery pk: 121 fields: save_id: gallery120 name: eg5_6 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.6) Describe the dynamic behaviour of the given circuit' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: capacitor;clock_c;constantvoltage;cscope;ground;inductor;resistor;split_f;step_function;switch;text_f;voltagesensor media: gallery120.png script_dump: '' - model: saveAPI.gallery pk: 122 fields: save_id: gallery121 name: eg5_7 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.7) Obtain the critically damped response for the circuit' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: capacitor;clock_c;constantvoltage;cscope;ground;inductor;resistor;split_f;step_function;switch;text_f;voltagesensor media: gallery121.png script_dump: '' - model: saveAPI.gallery pk: 123 fields: save_id: gallery122 name: eg5_8 description: 'Electrical Engineering Fundamentals (Author: V. Del Toro), 5) Circuit dynamics and forced responses, 5.8) Repeat the previous example for the case where the resistance R is changed' save_time: 2025-05-08 12:24:29+00:00 book: 293 data_dump: blocks: capacitor;clock_c;constantvoltage;cscope;ground;inductor;resistor;split_f;step_function;switch;text_f;voltagesensor media: gallery122.png script_dump: '' - model: saveAPI.gallery pk: 124 fields: save_id: gallery123 name: Ex6_14_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 6) The Frequency Response Design Method, 6.14) Lead compensation for DC motor' save_time: 2025-05-30 12:29:42+00:00 book: 3432 data_dump: blocks: clock_c;clr;const_f;cscope;dlr;gainblk;mux_f;ramp;split_f;step_function;summation;switch2_m;text_f media: gallery123.png script_dump: '//Example 6.14 //Lead compensation for DC motor. // the required value // for step response, set sw to 2 // for ramp response, set sw to 0 sw=2; Ts=1;' - model: saveAPI.gallery pk: 125 fields: save_id: gallery124 name: Ex7_32_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 7) State Space Design, 7.32) Redesign of the Dc servo compensator using SRL' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clksplit_f;clock_c;clr;cscope;dlr;mux_f;split_f;step_function;summation;text_f media: gallery124.png script_dump: '//------------------------------------------------------------------ //------------------------------------------------------------------ //A function written by Deepti Khimani. //Usage:- //p=zpk_dk(sl) //[p, z]=zpk_dk(sl) //[p, z, k]=zpk_dk(sl) //p:- Poles of the system //z:- zeros of the system //k:- DC gain of the system //------------------------------------------------------------------ //------------------------------------------------------------------ function[pl,zr,k]=zpk_dk(sysmodel) [lhs,rhs]=argn(0) if rhs == 0 then disp(["p=zpk_dk(sl)";"[p, z]=zpk_dk(sl)";"[p, z, k]=zpk_dk(sl)"]); disp(["p:- Poles of the system";"z:- zeros of the system"]); disp("k:- DC gain of the system"); return; end if typeof(sysmodel)=="rational" then sys=tf2ss(sysmodel); pl=spec(sys.A); zr=trzeros(sys); temp1=poly(zr,''s'',''roots'')/poly(pl,''s'',''roots''); temp2=sysmodel/temp1; temp3=tf2ss(temp2); k=temp3.D; elseif typeof(sysmodel)=="state-space" then pl=spec(sysmodel.A); zr=trzeros(sysmodel); g=ss2tf(sysmodel); temp1=poly(zr,''s'',''roots'')/poly(pl,''s'',''roots''); temp2=g/temp1; temp3=tf2ss(temp2); k=temp3.D else error("Wrong type of input argument.") end endfunction //Example 7.32 // Redesign of the Dc servo compensator using SRL // State space representation //Transfer function model for DC Servo s=poly(0,''s''); num=10; den=s*(s+2)*(s+8); Gs=syslin(''c'',num/den); // State space representation F=[-10 1 0;-16 0 1;0 0 0] G=[0 0 10]''; H=[1 0 0]; J=0; n=sqrt(length(F)); //Desired poles for the DC Servo system. Pc=[-2+1.56*%i -2-1.56*%i -8.04] // State feedback gain K=ppol(F,G,Pc) disp(K,''K='',"State feedback gain") //Estimator - error roots are at Pe=[-4+4.49*%i -4-4.49*%i -9.169] Lt=ppol(F'',H'',Pe); L=clean(Lt''); disp(L,''L='',"Observer gain") //Error in book, Gain values are different in book. //------------------------------------------------------------------ //Compensator Design DK=-K*inv(s*eye(n,n)-F+G*K+L*H)*L; DK=syslin(''c'',DK) [pl,zr,Kp]=zpk_dk(DK); Dc=poly(zr,''s'',''roots'')/poly(pl,''s'',''roots'') //------------------------------------------------------------------ //symmetric root locus G_s=horner(Gs,-s); //Discrete-time controller nc=94.5*conv([7.98 1],[2.52 1]) dc=conv([59.5348 8.56 1],[10.6 1]) sysDc=poly(nc,''s'',''coeff'')/poly(dc,''s'',''coeff''); sysDc_ss=syslin(''c'',tf2ss(sysDc)); ts=0.1; sysDd=dscr(sysDc_ss,ts) Gdz=ss2tf(sysDd); disp(sysDc,"Continuous-time compensator") disp(Gdz,"Discrete-time compensator")' - model: saveAPI.gallery pk: 126 fields: save_id: gallery125 name: Ex7_34_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 7) State Space Design, 7.34) Servomechanism increasing the velocity constant through zero assignment' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clock_c;clr;cscope;dlr;mux_f;split_f;step_function;summation;text_f media: gallery125.png script_dump: '//Example 7.34 // Servomechanism, increasing the velocity constant through // zero assignment. // State space representation //Transfer function model for DC Servo s=poly(0,''s''); num=1; den=s*(s+1); Gs=syslin(''c'',num/den); // State space representation F=[0 1;0 -1] G=[0 1]''; H=[1 0]; J=0; n=sqrt(length(F)); //Desired poles for the DC Servo system. Pc=[-2 -2] // State feedback gain //------------------------------------------------------------------ //------------------------------------------------------------------ //A function written by Deepti Khimani. //Usage:- //[K, lambda]=acker_dk(a, b, pl) //K=acker_dk(a, b, pl) //a:- System matrix. //b:- input matrix. //p:- Desired poles. //K:-State feedback gain for the control law u=-Kx. //lambda:- Eigen values of (a-b*k) //------------------------------------------------------------------ //------------------------------------------------------------------ function [K, lambda]=acker_dk(a, b, pl) [lhs,rhs]=argn(0) if rhs == 0 then disp(["K=acker_dk(a, b, pl)";"[K, lambda]=acker_dk(a, b, pl)"]); disp(["a:- System matrix";"b:- input matrix";"p:- Desired poles"]); disp(["K:-State feedback gain for the control law u=-Kx";... "lambda:- Eigen values of (a-b*k)"]); return; end [ra ca]=size(a); [rb cb]=size(b); l=length(pl); CO=cont_mat(a,b); if ra~=l then error(["Dimension error:";"number of desired poles must equal... to order of the system"]); elseif ra~=ca then error(["Dimension error:";"system matrix should be... a sqaure matrix"]); elseif rb~=ra then error (["Dimension error:","Input matrix should have... as many rows as a system matrix."]); elseif rank(CO) blocks: clock_c;clr;const;cscope;gainblk;gainblk_f;in_f;integral_f;out_f;split_f;summation;super_f;text_f media: gallery126.png script_dump: '//Example 7.35 // Integral Control of a Motor Speed System //Transfer function model num=1; s=poly(0,''s''); den=(s+3); G=syslin(''c'',num/den); sys=tf2ss(G) // State space representation of augmented system F=[0 1; 0 -3]; G=[0 1]''; H=[1 0]; J=0; //Desired poles for augmented system Pc=[-5 -5]; // State feedback gain is K=ppol(F,G,Pc) //Estimator Pe=[-10]; L=ppol(sys.A'',sys.C'',Pe) // (c) Compare step reference and disturbance response. // the required values // for step reference response switch, set r to 1 and w to 0 // for step disturbance response switch, set r to 0 and w to 1 r=1 w=0' - model: saveAPI.gallery pk: 128 fields: save_id: gallery127 name: Ex8_1_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 8) Digital Control, 8.1) Digital Controller using tustin approximation' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clksplit_f;clock_c;clr;cscope;dlr;gainblk;mux_f;split_f;step_function;summation;text_f media: gallery127.png script_dump: '///Example 8.1 // Digital Controller using tustin approximation. //Cntroller s=poly(0,''s''); numD=s/2+1; denD=s/10+1; D=10*numD/denD; Ds=syslin(''c'',D); //sampling freq. = 25 times bandwidth Wbw=10; Ws=25*Wbw; fs=Ws/2/%pi; T=1/fs; //sampling time a=1;b=-1; c=1;d=1; //Digital controller z=poly(0,''z''); Dz=horner(Ds,2/T*(a*z+b)/(c*z+d)); disp(Dz,''Digital Controller : '')' - model: saveAPI.gallery pk: 129 fields: save_id: gallery128 name: Ex8_2_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 8) Digital Control, 8.2) Design of a Space Station Attitude Digital Controller using Discrete Equivalents' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clock_c;clr;cscope;dlr;split_f;step_function;summation;text_f media: gallery128.png script_dump: '//Example 8.2 // Design of a Space Station Attitude Digital Controller using // Discrete Equivalents // State space representation of continuous time system s=poly(0,''s''); num=1; den=(s^2); Gs=syslin(''c'',num/den); Ds=0.81*(s+0.2)/(s+2); Ds=syslin(''c'',Ds); sysc=Gs*Ds; //Contonuous time response of the system tc=0:0.1:30; syscl=sysc/(1+sysc) yc=csim("step",tc,syscl); //------------------------------------------------------------------ // Discretization of the system at z=poly(0,''z'') // sampling time Ts=1 sec Ts=1; Dz1=horner(Ds,2/Ts*(z-1)/(z+1)) disp(Dz1,"Dz1=","Discrete-time controller with Ts=1 sec.") // sampling time Ts=0.5 sec Ts2=0.5; Dz2=horner(Ds,2/Ts2*(z-1)/(z+1)) disp(Dz2,"Dz2=","Discrete-time controller with Ts=0.5 sec.")' - model: saveAPI.gallery pk: 130 fields: save_id: gallery129 name: Ex9_11_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.11) Describing Function for a relay with hysteresis non linearity' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clock_c;cscope;endblk;gensin_f;hystheresis;mux_f;split_f;text_f media: gallery129.png script_dump: '//Example 9.11 //Describing Function for a relay with hysteresis nonlinearity. //Response of the saturation noninearity to sinusoidal input ////Describing Functin for relay with hysteresis nonlinearity. h=0.1; N=1; i=1; for a=0.1:0.025:1 if a blocks: clock_c;clr;const;cscope;endblk;hystheresis;summation;text_f media: gallery130.png script_dump: '//Example 9.13 //Determination of stability with a hysteresis nonlinearity. //System Model s=poly(0,''s''); num=1; den=(s^2+s); Gs=syslin(''c'',num/den); // Nyquist Plot of Describing Function for hysteresis nonlinearity N=1; h=0.1; i=1; for omegat=0:0.05:%pi-0.1; a=sin(omegat); DF_nyq(i,1)=-%pi/4/N*(sqrt(a^2-h^2) + h * %i); i=i+1; end //Response of the system K=2; // the required value r=1' - model: saveAPI.gallery pk: 132 fields: save_id: gallery131 name: Ex9_5_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.5) Changing Overshoot and Saturation nonlinearity' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clksplit_f;clock_c;clr;const;cscope;endblk;gainblk;saturation;summation;text_f media: gallery131.png script_dump: '//Example 9.5 //Changing Overshoot and Saturation nonlinearity. //System transfer function and its root locus s=poly(0,''s''); num=(s+1) den=(s^2); Gs=syslin(''c'',num/den) // Step response K=1; i=[2 4 6 8 10 12]; r=2' - model: saveAPI.gallery pk: 133 fields: save_id: gallery132 name: Ex9_6_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.6) Stability of conditionally stable system using root locus' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clock_c;clr;const;cscope;endblk;gainblk;saturation;summation;text_f media: gallery132.png script_dump: '//Example 9.6 //Stability of conditionally stable system using root locus. //System transfer function and its root locus s=poly(0,''s''); num=(s+1)^2 den=(s^3); Gs=syslin(''c'',num/den) //Response of the system K=2; i=[1 2 3 3.475]; r=1' - model: saveAPI.gallery pk: 134 fields: save_id: gallery133 name: Ex9_7_model_notch description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.7) Analysis and design of the system with limit cycle using the root locus' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: '' blocks: clock_c;clr;const;cscope;endblk;gainblk;saturation;summation;text_f media: gallery133.png script_dump: '//Example 9.7 //Analysis and design of the system with limit cycle using the root locus. //System transfer function and its root locus s=poly(0,''s''); num=0.1; den=(s^2+0.2*s+1)*(s); Gs=syslin(''c'',num/den); //Response of the system K=0.5; i=[1 4 8]; r=1 //System with notch compensation D=123*(s^2+0.18*s+0.81)/(s+10)^2; //Response of the system witth notch filter K=0.5; i=[2 4]; r=2' - model: saveAPI.gallery pk: 135 fields: save_id: gallery134 name: Ex9_7_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.7) Analysis and design of the system with limit cycle using the root locus' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: '' blocks: clock_c;clr;const;cscope;endblk;gainblk;saturation;summation;text_f media: gallery134.png script_dump: '//Example 9.7 //Analysis and design of the system with limit cycle using the root locus. //System transfer function and its root locus s=poly(0,''s''); num=0.1; den=(s^2+0.2*s+1)*(s); Gs=syslin(''c'',num/den); //Response of the system K=0.5; i=[1 4 8]; r=1 //System with notch compensation D=123*(s^2+0.18*s+0.81)/(s+10)^2; //Response of the system witth notch filter K=0.5; i=[2 4]; r=2' - model: saveAPI.gallery pk: 136 fields: save_id: gallery135 name: Ex9_8_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.8) Antiwindup compensation for a PI controller' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clksplit_f;clock_c;clr;cscope;endblk;gainblk;saturation;split_f;step_function;summation;text_f media: gallery135.png script_dump: '//Example 9.8 //Antiwindup compensation for a PI controller. //System Model //Response of the system kp=2; ki=4; //Without antiwindup ka=0; //With antiwindup ka=10;' - model: saveAPI.gallery pk: 137 fields: save_id: gallery136 name: Ex9_9_model description: 'Feedback Control of Dynamic Systems (Author: G. F. Franklin, J. D. Powell and A. Emami-Naeini), 9) Nonlinear Systems, 9.9) Describing Function for a saturation nonlinearity' save_time: 2025-05-08 12:24:29+00:00 book: 3432 data_dump: blocks: clock_c;cscope;endblk;gensin_f;mux_f;saturation;split_f;text_f media: gallery136.png script_dump: '//Example 9.9 //Describing Function for a saturation nonlinearity. //Response of the saturation nonlinearity to sinusoidal input //Describing Functin for saturation nonlinearity. k=1; N=1; i=1; Keq=[]; for a=0:0.2:10 if k*a/N > 1 then Keq(i,1)=2/%pi*(k*asin(N/a/k)+N/a*sqrt(1-(N/k/a)^2)) else Keq(i,1)=k end i=i+1; end a=0:0.2:10; a=a'';' - model: saveAPI.gallery pk: 138 fields: save_id: gallery137 name: Ex3_1 description: 'Control Systems (Author: A Nagoor Kani), 3) TIME RESPONSE ANALYSIS, 3.1) RESPONSE OF THE SYSTEM' save_time: 2025-05-08 12:24:29+00:00 book: 3885 data_dump: blocks: bigsom_f;clock_c;clr;cscope;step_function media: gallery137.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 3.1 s=%s p=poly([4],''s'',''coeff'') q=poly([0 5 1],''s'',''coeff'') g=p./q disp(g,''The given transfer function is'') c=g/(1+g) disp(c,''The closed loop transfer function is'') u=c/s disp(u,''The input is unit step signal'')' - model: saveAPI.gallery pk: 139 fields: save_id: gallery138 name: Ex3_2 description: 'Control Systems (Author: A Nagoor Kani), 3) TIME RESPONSE ANALYSIS, 3.2) RESPONSE OF THE SYSTEM' save_time: 2025-05-08 12:24:29+00:00 book: 3885 data_dump: blocks: clock_c;clr;cscope;step_function media: gallery138.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 3.2 s=%s p=poly([100],''s'',''coeff'') q=poly([0 2 1],''s'',''coeff'') h=poly([1 0.1 0 ],''s'',''coeff'') g=p./q disp(g,''the given transfer function is'') c=g/(1+(g*h)) disp(c,''the closed loop transfer function is'') u=c/s disp(u,''the in put is unit step signal'')' - model: saveAPI.gallery pk: 140 fields: save_id: gallery139 name: Ex3_6 description: 'Control Systems (Author: A Nagoor Kani), 3) TIME RESPONSE ANALYSIS, 3.6) RESPONSE OF THE SYSTEM' save_time: 2025-05-08 12:24:30+00:00 book: 3885 data_dump: blocks: clock_c;clr;cscope;step_function media: gallery139.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 3.6 s=poly(0,''s'') // the input is unit step signal h=syslin(''c'',16/(s^2+4*s+16))//the value of k is 0.2 zeta=0.5//given damping ratio disp(h,''the closed loop transfer function'') //standard form od second order system is w^2/s^2+2*zeta*w*s+w^2 //compaing h with the standard form w=4//natural frequency of oscillation disp(w,''natural frequency of oscillation in rad/sec'') k=(2*zeta*w-(0.8))/16 disp(k,''the value of k is'') mp=exp((-zeta*%pi)/sqrt(1-(zeta)^2))*100//percentage peak overshoot disp(mp,''percentage peak overshoot in percentage'') tp=%pi/(w*sqrt(1-(zeta)^2)) disp(tp,''peak time in seconds'') //constructing a right angle triangle with zeta and sqrt(1-zeta^2) theta=atan(0.866/0.5)//(1-zeta^2)/zeta disp(theta,''the value of theta is'') tr=(%pi- theta)/(w*sqrt(1-(zeta)^2)) disp(tr,''the rise time in seconds'') t=1/(zeta*w)//time constant ts1=3*t//settling time for 5% error disp(ts1,''settling time for 5% error in seconds'') ts2=4*t//settling time for 2% error disp(ts2,''settling time for 2% error in seconds'')' - model: saveAPI.gallery pk: 141 fields: save_id: gallery140 name: Ex3_7 description: 'Control Systems (Author: A Nagoor Kani), 3) TIME RESPONSE ANALYSIS, 3.7) RESPONSE OF THE SYSTEM' save_time: 2025-05-08 12:24:30+00:00 book: 3885 data_dump: blocks: clock_c;clr;cscope;step_function media: gallery140.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 3.7 s=%s p=poly([1 0.4 0 ],''s'',''coeff'') q=poly([0 0.6 1],''s'',''coeff'') g=p./q disp(g,''the given transfer function is'') c=g/(1+g) disp(c,''the closed loop transfer function is'') u=c/s disp(u,''the in put is unit step signal'') //standard form od second order system is w^2/s^2+2*zeta*w*s+w^2 //compaing h with the standard form w=1//natural frequency of oscillation disp(w,''natural frequency of oscillation in rad/sec'') zeta=1/(2*w) disp(zeta,''the damping ratio is'') mp=exp((-zeta*%pi)/sqrt(1-(zeta)^2))*100//percentage peak overshoot disp(mp,''percentage peak overshoot in percentage'') tp=%pi/(w*sqrt(1-(zeta)^2)) disp(tp,''peak time in seconds'')' - model: saveAPI.gallery pk: 142 fields: save_id: gallery141 name: Ex7_10 description: 'Control Systems (Author: A Nagoor Kani), 7) STATE SPACE ANALYSIS, 7.10) STATE MODEL' save_time: 2025-05-08 12:24:30+00:00 book: 3885 data_dump: blocks: clock_c;clss;cscope;step_function media: gallery141.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 7.10 s=%s p=poly([10],''s'',''coeff'') q=poly([1 2 4 1],''s'',''coeff'') sm=cont_frm(p,q) disp(sm,''the state model in matrix form is'')' - model: saveAPI.gallery pk: 143 fields: save_id: gallery142 name: Ex7_11 description: 'Control Systems (Author: A Nagoor Kani), 7) STATE SPACE ANALYSIS, 7.11) STATE MODEL' save_time: 2025-05-08 12:24:30+00:00 book: 3885 data_dump: blocks: clock_c;clss;cscope;step_function media: gallery142.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 7.11 s=%s p=poly([40 10],''s'',''coeff'') q=poly([0 3 4 1],''s'',''coeff'') sm=cont_frm(p,q) disp(sm,''the state model in matrix form is'')' - model: saveAPI.gallery pk: 144 fields: save_id: gallery143 name: Ex7_12 description: 'Control Systems (Author: A Nagoor Kani), 7) STATE SPACE ANALYSIS, 7.12) STATE MODEL' save_time: 2025-05-08 12:24:30+00:00 book: 3885 data_dump: blocks: clock_c;clss;cscope;step_function media: gallery143.png script_dump: '//control systems by Nagoor Kani A //Edition 3 //Year of publication 2015 //Scilab version 6.0.0 //operating systems windows 10 // Example 7.12 s=%s h=syslin(''c'',(2*(s+5))/((s+2)*(s+3)*(s+4))) disp(h,''thr transfer function is'') ss=tf2ss(h) disp(ss,''the state space model is'') [Ac,Bc,U,ind]=canon(ss(2),ss(3)) disp(Ac,Bc,U,ind)' - model: saveAPI.gallery pk: 145 fields: save_id: gallery144 name: example_11_1 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 11) Unsymmetrical Fault Analysis, 11.1) LG and 3Phase faults Comparision' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;sinevoltage;split_f;step_function;switch;text_f media: gallery144.png script_dump: '//Chapter 11 //Example 11.1 //page 406 //To draw sequence networks of generator and to compare LG fault current will be greater than three-phase fault current when neutral is solidly grounded disp("Sequence networks of synchronous generator grounded through neutral impedance has been drawn using XCOS "); disp("Since the derivation can not be done here, let us do this problem by taking a suitable values for the sequence reactances of the generator"); disp("X1=j0.18, X2=j0.15, X0=j0.10 pu and Ea=1"); disp("From the figs 11.13 and 11.14 in the textbook,we can find Ilg and I3L"); Ea=1;X1=0.18*%i;X2=0.15*%i;X0=0.10*%i; IaLG=3*Ea/(2*X1+X0) Ia3L=3*Ea/(3*X1) disp("Same values of sequence impedance have been used in XCOS simulation also to varify the result");' - model: saveAPI.gallery pk: 146 fields: save_id: gallery145 name: example_11_2 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 11) Unsymmetrical Fault Analysis, 11.2) Grounding Resistor voltage and Fault Current' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;resistor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery145.png script_dump: '//Chapter 11 //Example 11.2 //page 408 //To find fault current and voltage across the grounding resistor X1eq=(%i*0.18)/2; X2eq=(%i*0.15)/2; Z0eq=(%i*0.10)+3*(2*20/(11^2)); Ea=1; //calculation of fault current printf(''\nFault current is given by ''); If=(3*Ea)/(X1eq+X2eq+Z0eq) //current in grounding resistor Ifg=abs(If)*(20/(11*sqrt(3))); printf(''\n\nCurrent through grounding resistor Ifg=%0.2fkA'',Ifg); //voltage across grounding resistor Vgr=abs(If*(2*20/(11^2))*(11/sqrt(3))); printf(''\n\nVoltage across grounding resistor Vgr=%0.2fkV\n\n'',Vgr);' - model: saveAPI.gallery pk: 147 fields: save_id: gallery146 name: example_11_3 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 11) Unsymmetrical Fault Analysis, 11.3) Fault and subtransient currents of the system' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;mux;sinevoltage;split_f;step_function;switch;text_f media: gallery146.png script_dump: '//Chapter 11 //Example 11.3 //page 409 //To find fault current and subtransient current in all parts of the system a=-0.5+(sqrt(3)/2)*%i; //neglecting prefault currents Vf0=10/11; Eg=Vf0; Em1=Vf0 ;Em2=Vf0; //positive sequence network when it is replaced by its thevenin''s equvivalent as shown in fig11.18 printf(''\nsequence impedances are given by \n''); Z1=(%i*0.525*%i*0.23)/(%i*0.755); Z2=Z1; Z0=%i*1.712; printf(''Z1=j%0.4f \nZ2=j%0.4f \nZ0=j%0.4f'',abs(imag(Z1)),abs(imag(Z2)),abs(imag(Z0))); //to find sequence current Ia1=Vf0/(Z1+Z2+Z0); Ia2=Ia1; Ia0=Ia1; //to find fault current If=3*Ia0; printf(''\n\nFault Current= -j%0.4f'',abs(imag(If))); //component current flowing from generator and motor printf(''\n\nComponents currents flowing from Generator and motor are \n'') Ig1=Ia1*(0.23/0.755) ; Ig2=Ig1; Ig0=0; printf(''Ig1= -j%0.4f \nIg2= -j%0.4f \nIg0=%d'',abs(Ig1),abs(Ig2),abs(Ig0)); printf(''\n''); Im1=Ia1*(0.525/0.755); Im2=Im1; Im0=Ia0; printf(''\nIm1= -j%0.4f \nIm2= -j%0.4f \nIm0= -j%0.4f'',abs(Im1),abs(Im2),abs(Im0)); //fault currents from the generator and motor towards g are printf(''\n\nFault current from the generator towards g are ''); Ig=[1 1 1;a^2 a 1;a a^2 1]*[Ig1;Ig2;Ig0]; disp(Ig); printf(''and to g from motors are''); Im=[1 1 1;a^2 a 1;a a^2 1]*[Im1;Im2;Im0]; disp(Im); printf(''\nPositive sequence current =%0.3f pu'',(-%i*Ig1)); printf(''\nNegative sequence current =%0.3f pu'',(%i*Ig2)); printf(''\nZero sequence current=%d\n'',Ig0); //under loaded condition,PU motor currents are Im1o=(15/(25*0.909*0.8))*(0.800103636+%i*0.5998617938); Im2o=(7.5/(25*0.909*0.8))*(0.800103636+%i*0.5998617938); printf(''\nThe per unit motor currents are:\n''); printf(''Motor1:%0.2f +j%0.3f pu'',real(Im1o),imag(Im1o)); printf(''\nMotor2:%0.2f +j%0.3f pu'',real(Im2o),imag(Im2o)); //the voltages behind subtransient reactances are calculated below printf(''\n\nVoltage behind subtransient reactances:\n''); printf(''Motor1:''); Em1=Em1-(%i*0.345*Im1o); printf(''Em1= %0.4f-j%0.4f'',real(Em1),abs(imag(Em1))); printf(''\nMotor2:''); Em2=Em2-(%i*0.69*Im2o); printf(''Em2= %0.4f-j%0.4f'',real(Em2),abs(imag(Em2))); printf(''\nGenerator:''); Eg=Eg+(%i*0.525*(Im2o+Im1o)); printf(''Eg= %0.4fj+%0.4f'',real(Eg),abs(imag(Eg))); //actual value of positive sequence current from generator and motor printf(''\n\nThe actual value of positive sequence current from the generator towards fault is = %0.2f+j%0.3f'',real(Im1o+Im2o+Ig1),imag(Im1o+Im2o+Ig1)); printf(''\nThe actual value of positive sequence current from the motors towards fault is = %0.2f-j%0.3f'',real(-Im1o-Im2o+Im1),abs(imag(-Im1o-Im2o+Im1)));' - model: saveAPI.gallery pk: 148 fields: save_id: gallery147 name: example_11_4 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 11) Unsymmetrical Fault Analysis, 11.4) LL Fault Current' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery147.png script_dump: '//Chapter 11 //Example 11.4 //page 412 //To find L-L fault current and voltage of healthy phase X1eq=0.09*%i; X2eq=0.075*%i; Z0=0.99+(%i*0.1); Ea=1;Ia0=0; //to calculate Ia1 Ia1=Ea/(X1eq+X2eq); //to calculate fault current If=(-%i*sqrt(3))*(-%i*6.06); Va1=Ea-(Ia1*X1eq); Va0=(-Ia0*Z0); Va2=Va1; //voltage in healthy phase Va=Va1+Va2+Va0; //displaying the result printf(''\nIa1=-j%0.2f'',abs(Ia1)); printf(''\nIf=%0.3f'',If); printf(''\nVa1=Va2=%0.3f'',Va1); printf(''\nVa0=%d'',Va0); printf(''\nVa=Va1+Va2+Va0=%0.2f\n\n'',Va);' - model: saveAPI.gallery pk: 149 fields: save_id: gallery148 name: example_11_5 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 11) Unsymmetrical Fault Analysis, 11.5) Double line to ground Fault' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;mux;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery148.png script_dump: '//Chapter 11 //Example 11.5 //page 413 //To find Double line to ground fault current and voltage of healthy phase Z1eq=0.09*%i; Z2eq=0.075*%i; Z0=(%i*0.1); Ea=1; a=(-0.5+%i*sqrt(3)/2); //to find the sequence components of healthy phase Ia1=Ea/(Z1eq+(Z2eq*Z0/(Z2eq+Z0))); Va1=Ea-(Ia1*Z1eq); Va2=Va1; Va0=Va1; Ia2=-(Va2/Z2eq); Ia0=-(Va0/Z0); I=[1 1 1;a^2 a 1;a a^2 1]*[Ia1; Ia2; Ia0]; //voltage of the healthy phase Va=3*Va1; //displaying the results printf(''Ia1=-j%0.3f\n'',abs(Ia1)); printf('' Ia2=j%0.3f\n'',abs(Ia2)); printf('' Ia0=j%0.3f\n\n'',abs(Ia0)); printf('' Ia=%0.3f + j%0.3f\n'',real(I(1,1)),imag(I(1,1))); printf('' Ib=%0.3f + j%0.3f\n'',real(I(2,1)),imag(I(2,1))); printf('' Ic=%0.3f + j%0.3f\n\n'',real(I(3,1)),imag(I(3,1))); printf('' Voltage of the healthy phase Va=3Va1=%0.3f'',Va);' - model: saveAPI.gallery pk: 150 fields: save_id: gallery149 name: example_9_1_3phase_plot description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 9) Symmetrical Fault Analysis, 9.1) Fault Current Calculation' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: '' blocks: clock_f;cmscope;currentsensor;ground;inductor;resistor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery149.png script_dump: '//Chapter 9 //Example 9.1 //page 335 //To calculate fault current //selecting base KVA and MVA mvab=100; Gmva=10; T1mva=10; T2mva=5; Gkvb=11; //generator kV base OHLkvb=33; //overhead line kV base Ckvb=6.6;// cable kB base xg1=%i*0.15; xg2=%i*0.125; xt1=%i*0.10; xt2=%i*0.08; xOHL=0.27+%i*0.36 ; xcab= 0.135+%i*0.08; //clculating PU impedances xg1=(xg1*mvab)/Gmva; xg2=(xg2*mvab)/Gmva; xt1=(xt1*mvab)/T1mva; xt2=(xt2*mvab)/T2mva; xOHL=(30*xOHL*mvab)/(OHLkvb^2); xcab=(3*xcab*mvab)/(Ckvb^2); //displaying results printf(''\n Reactance of G1= j%0.1f pu \n'',abs(imag(xg1))); printf('' Reactance of G2= j%0.1f pu\n'',abs(imag(xg2))); printf('' Reactance of T1= j%0.1f pu\n'',abs(imag(xt1))); printf('' Reactance of T2= j%0.1f pu\n'',abs(imag(xt2))); printf('' Overhead line impedance=(%0.3f + j%0.3f) pu\n'',real(xOHL),abs(imag(xOHL))); printf('' Cable impedance= (%0.3f + j%0.3f) pu\n'',real(xcab),abs(imag(xcab))); // Impedance diagram is as shown in the figure9.7 in the textbook // A XCOS simulation for this proble is done to explain the subtransient,transient and steady state periods of a symmetrical short circuit xtotal=((xg1*xg2)/(xg1+xg2)+xt1+xt2+xOHL+xcab); Isc_pu=(1/xtotal); Ibase=(mvab/(sqrt(3)*Ckvb))*1000; Isc=Isc_pu*Ibase; x_F_to_bus=(xt1+xt2+xOHL+xcab); v_11b=x_F_to_bus*Isc_pu*11; //displaying results printf(''\nTotal impedance= %0.1f < %0.2f deg pu \n'',abs(xtotal),atand(imag(xtotal)/real(xtotal))); printf(''Short circuit current= %d A\n'',abs(Isc)); printf(''Voltage at 11kV bus=%0.2f kV\n'',abs(v_11b));' - model: saveAPI.gallery pk: 151 fields: save_id: gallery150 name: example_9_2 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 9) Symmetrical Fault Analysis, 9.2) Subtransient and Momentary current Calculation' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery150.png script_dump: '//Chapter 9 //Example 9.2 //page 337 //To calculate subtransient and momentary current mvab=25; Gmva=25; T1mva=25; T2mva=25; Gkvb=11; //generator kV base OHLkvb=66; //overhead line kV base Mkvb=6.6; //motor kV base Mmva=5; //motor mva XdG=%i*0.2; //Generator''s subtransient reactance XdM=%i*0.25; //Motor''s subtransient reactance XdM2=%i*0.3; //Motor''s transient reactance Xt1=%i*0.1; // step up transformer''s reactance Xt2=%i*0.1;//step down transformer''s reactance Xtl=%i*0.15 ;//trnasmission line''s reactance //per unit calculation XdM=(XdM*mvab)/Mmva ;//perunit impedance of each motor printf(''\nSubtransient reactance of each motor = j%0.2f pu\n'',abs(XdM)); //(a)subtransient current in the fault Isc=(3*(1/XdM))+(1/(XdG+Xt1+Xt2+Xtl)); Ibase=(mvab*1000)/(sqrt(3)*Mkvb); Isc=Isc*Ibase; printf(''\nSubtransient current in the fault =%0.1fA\n'',abs(Isc)); //(b)subtransient current in the breaker B IscB=(2*(1/XdM))+(1/(XdG+Xt1+Xt2+Xtl)); IscB=IscB*Ibase; printf(''\nSubtransient current in breaker B=%0.1fA\n'',abs(IscB)); //(c) to find the momentary current through breaker B ImomB=1.6*IscB; printf(''\nMomentary current through the breaker B=%dA\n'',abs(ImomB)); //(d) to compute current to be interrupted by breaker in 5 cycles XdM2=(XdM2*mvab)/Mmva ;//perunit transient impedance of each motor IscB=(2*(1/XdM2))+(1/(XdG+Xt1+Xt2+Xtl)); IscB=IscB*Ibase; ImomB=1.1*IscB; printf(''\nCurrent to be interrupted by breaker B in five cycles=%dA\n'',abs(ImomB));' - model: saveAPI.gallery pk: 152 fields: save_id: gallery151 name: example_9_3 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 9) Symmetrical Fault Analysis, 9.3) Subtransient Current Calculation' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery151.png script_dump: '//Chapter 9 //Example 9.3 //page 340 //To calculate subtransient current in Generator,Motor and fault mvab=25; kvb=11; Vo=10.6/kvb; //PU Prefault voltage printf(''\nPrefault Voltage = %0.4fpu\n'',Vo); Load=15/mvab; //load PU with 0.8pf leading Io=(Load/(Vo*0.8))*(cosd(36.9)+%i*sind(36.9)); //Prefault current printf(''\nPrefault current = %0.4f at %0.1f deg PU'',abs(Io),atand(imag(Io)/real(Io))); Eg=Vo+(%i*0.45*Io); //voltage behind subtransient reactance(generator) printf(''\n\nVoltage behind subtransient reactance(Generator) = %0.4f+j%0.2f pu\n'''''',real(Eg),imag(Eg)); Em=Vo-(%i*0.15*Io); //voltage behind subtransient reactance(motor) printf(''\nVoltage behind subtransient reactance(Motor) = %0.4f-j%0.4f pu'',real(Em),abs(imag(Em))); Ig=Eg/(%i*0.45); //under fault condition Im=Em/(%i*0.15); //under fault condition printf(''\n\nUnder Faulted condition \n Ig""=%0.4f-j%0.4f pu'',real(Ig),abs(imag(Ig))); printf(''\n Im""=%0.4f-j%0.4f pu'',real(Im),abs(imag(Im))); If=Ig+Im; //Current in fault printf(''\n\nCurrent in fault= -j%0.4f pu'',abs(imag(If))); Ib=(mvab*1000/(sqrt(3)*11)); //Base current //Actual Currents printf("\n\nNow"); Ig=Ig*Ib Im=Im*Ib If=If*Ib printf(''\nIg""= %0.1f-j%0.1f A'',real(Ig),abs(imag(Ig))); printf(''\nIm""= %0.1f-j%0.1f A'',real(Im),abs(imag(Im))); printf(''\nIf= -j%d A'',abs(imag(If)));' - model: saveAPI.gallery pk: 153 fields: save_id: gallery152 name: example_9_4 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 9) Symmetrical Fault Analysis, 9.4) Maximum MVA Calculation' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;resistor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery152.png script_dump: '//Chapter 9 //Example 9.4 //page 345 //To calculate maximum MVA mvab=50; kvb=6.6; mvaA=40; mvaB=50; mvaC=25; feeder_impedance=((0.06+%i*0.12)*mvab)/(kvb^2) Gen_A_reactance=(%i*0.1*mvab/mvaA); Gen_B_reactance=(%i*0.1*mvab/mvaB); Gen_C_reactance=(%i*0.1*mvab/mvaC); printf(''\nGenerator A reactance = j%0.3f pu'',abs(Gen_A_reactance)); printf(''\nGenerator B reactance = j%0.3f pu'',abs(Gen_B_reactance)); printf(''\nGenerator C reactance = j%0.3f pu'',abs(Gen_C_reactance)); Reactor_A_reactance=(%i*0.12*mvab/mvaA); Reactor_B_reactance=(%i*0.12*mvab/mvaB); Reactor_C_reactance=(%i*0.12*mvab/mvaC); printf(''\nReactor A reactance = j%0.3f pu'',abs(Reactor_A_reactance)); printf(''\nReactor B reactance = j%0.3f pu'',abs(Reactor_B_reactance)); printf(''\nReactor C reactance = j%0.3f pu'',abs(Reactor_C_reactance)); function resistance=parallel(r1,r2) resistance=(r1*r2/(r1+r2)); endfunction Z=(feeder_impedance)+parallel(%i*0.125,(%i*0.15 + parallel(%i*0.22,%i*0.44))); scmva=(1/abs(Z))*mvab; printf("\n\nSC MVA = %d MVA",scmva);' - model: saveAPI.gallery pk: 154 fields: save_id: gallery153 name: example_9_5 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 9) Symmetrical Fault Analysis, 9.5) Short Circuit Solution' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: clock_c;cmscope;currentsensor;ground;inductor;sinevoltage;split_f;step_function;switch;text_f;voltagesensor media: gallery153.png script_dump: '//Chapter 9 //Example 9.5 //page 347 //To calculate short circuit solution //referring to figures 9.19 in the text book,we get directly the fault current V4o=1.0; Zf=%i*0.13560; If=V4o/Zf; printf(''\nIf= -j%0.5f pu\n\n'',abs(If)); //From Fig9.19d I1=If*((%i*0.19583)/(%i*0.37638)); I2=If*((%i*0.18055)/(%i*0.37638)); printf(''I1 = -j%0.5f pu \n\nI2 = -j%0.5f pu\n\n'',abs(I1),abs(I2)); //voltage changes for bus 1,2 and 3 deltaV1=0-(%i*0.15)*I1; deltaV2=0-(%i*0.15)*I2; printf(''DeltaV1=%0.5f pu\n\nDeltaV2=%0.5f pu\n\n'',deltaV1,deltaV2); //reffering to book V1f=1+deltaV1; V2f=1+deltaV2; printf(''V1f= %0.5f pu\n\nV2f=%0.5f pu\n\n'',V1f,V2f); I13=(V1f-V2f)/(%i*0.15+%i*0.1); printf(''I13=j%0.5f pu\n\n'',abs(I13)); deltaV3=0-((%i*0.15)*(I1)+(%i*0.15)*(I13)); Vf3=1+deltaV3; printf(''DeltaV3=%0.5f pu\n\n'',deltaV3); printf(''Vf3=%0.5f pu\n\n'',Vf3); Vf4=0; printf(''Vf4=%d\n\n'',Vf4); //short circuit MVA at bus 4 SC_MVA_4=abs(If)*100; printf(''Short circuit MVA at bus4 =%0.3f MVA'',SC_MVA_4);' - model: saveAPI.gallery pk: 155 fields: save_id: gallery154 name: example_9_7 description: 'Modern Power System Analysis (Author: D. P. Kothari And I. J. Nagrath), 9) Symmetrical Fault Analysis, 9.7) Current Injection Method' save_time: 2025-05-08 12:24:30+00:00 book: 83 data_dump: blocks: ccs;clock_c;cmscope;ground;resistor;split_f;step_function;text_f;voltagesensor media: gallery154.png script_dump: '//Chapter 9 //Example 9.7 //page 355 //To evaluate Zbus using Current Injection method disp("We can approach this problem using XCOS simulation") disp("In this simulation"); disp("1)For injecting unit current at bus1 keeping bus2 open circuit,we use a current source of 1 unit which is switched on from t=0 to t=2. During this period we can observe the voltage waveforms of V1 and V2 and compare with the results given in the textbook"); disp("2)For injecting unit current at bus2 keeping bus1 open circuit,we use a current source of 1 unit which is switched on from t=4 to t=6. During this period we can observe the voltage waveforms of V1 and V2 and compare with the results given in the textbook"); Z11=7; Z21=4; Z12=Z21; Z22=6; Zbus=[Z11 Z12;Z21 Z22]'