// Scilab ( http://www.scilab.org/ ) - This file is part of Scilab // Copyright (C) INRIA - // // This file must be used under the terms of the CeCILL. // This source file is licensed as described in the file COPYING, which // you should have received as part of this distribution. The terms // are also available at // http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt function [frq, bnds, splitf] = calfrq(h, fmin, fmax) //! eps = 1.d-14 //minimum absolute lower frequency k = 0.001 // Minimum relative prediction error in the nyquist plan epss = 0.002 // minimum frequency distance with a singularity nptmax = 5000 //maximum number of discretization points tol = 0.01 // Tolerance for testing pure imaginary numbers // Check inputs // ------------ if and(typeof(h) <> ["state-space" "rational"]) error(msprintf(gettext("%s: Wrong type for input argument #%d: Linear state space or a transfer function expected.\n"), "calfrq", 1)) end if typeof(h) == "state-space" then h = ss2tf(h) end [m, n] = size(h.num) dom = h("dt") select dom case "d" then dom = 1 case [] then error(96, 1) case 0 then error(96, 1) end; if type(dom) == 1 then nyq_frq = 1/2/dom; if fmax > nyq_frq then warning(msprintf(gettext("%s: Frequencies beyond Nyquist frequency are ignored.\n"), "calfrq")); fmax = min(fmax, nyq_frq) end if fmin < -nyq_frq then warning(msprintf(gettext("%s: Negative frequencies below Nyquist frequency are ignored.\n"), "calfrq")); fmin = max(fmin, -nyq_frq) end end // Use symmetry to reduce the range // -------------------------------- if fmin < 0 & fmax >= 0 then [frq, bnds, splitf] = calfrq(h, eps, -fmin) ns1 = size(splitf, "*")-1; nsp = size(frq, "*"); bnds = [bnds(1), bnds(2), -bnds(4), -bnds(3)]; if fmax > eps then if fmax == -fmin then splitf = [1, (nsp+2)*ones(1,ns1)-splitf($:-1:2), nsp*ones(ns1)+splitf(2:$)]; bnds = [bnds(1), bnds(2), min(bnds(3), -bnds(3)), max(bnds(4), -bnds(4))]; frq = [-frq($:-1:1), frq] else [frq2, bnds2, splitf2] = calfrq(h, eps, fmax); ns2 = size(splitf2,"*")-1 splitf = [1, (nsp+2)*ones(1,ns1)-splitf($:-1:2), nsp*ones(ns2)+splitf2(2:$)]; bnds = [min(bnds(1), bnds2(1)), max(bnds(2), bnds2(2)),... min(bnds(3), bnds2(3)), max(bnds(4), bnds2(4))]; frq = [-frq($:-1:1), frq2] end return else frq = -frq($:-1:1); nsp = size(frq, "*"); splitf = [1, (nsp+2)*ones(1, ns1)-splitf($:-1:2)] bnds = bnds; return; end elseif fmin < 0 & fmax <= 0 then [frq, bnds, splitf] = calfrq(h, -fmax, -fmin) ns1 = size(splitf, "*")-1; frq = -frq($:-1:1); nsp = size(frq, "*"); splitf = [1, (nsp+2)*ones(1, ns1)-splitf($:-1:2)] bnds = [bnds(1), bnds(2), -bnds(4), -bnds(3)]; return; elseif fmin >= fmax then error(msprintf(gettext("%s: Wrong value for input arguments #%d and #%d: %s < %s expected.\n"),.. "calfrq", 2, 3, "fmin", "fmax")); end // Compute dicretisation over a given range // ---------------------------------------- splitf = [] if fmin == 0 then fmin = min(1d-14, fmax/10);end // denh = h("den"); numh = h("num") l10 = log(10) // Locate singularities to avoid them // ---------------------------------- if dom == "c" then c = 2*%pi; // selection function for singularities in the frequency range deff("f=%sel(r, fmin, fmax, tol)",["f = [],"; "if prod(size(r)) == 0 then return, end"; "f = imag(r(find((abs(real(r))<=tol*abs(r))&(imag(r)>=0))))"; "if f <> [] then f = f(find((f>fmin-tol)&(f<fmax+tol))); end"]); else c = 2*%pi*dom // selection function for singularities in the frequency range deff("[f] = %sel(r, fmin, fmax, dom, tol)",["f = [],"; "if prod(size(r)) == 0 then return, end"; "f = r(find( ((abs(abs(r)-ones(r)))<=tol)&(imag(r)>=0)))"; "if f <> [] then "; " f = atan(imag(f), real(f)); nf = prod(size(f))"; " for k=1:nf,"; " kk = int((fmax-f(k))/(2*%pi))+1;"; " f = [f; f(1:nf)+2*%pi*kk*ones(nf, 1)];"; " end;" " f = f(find((f>fmin-tol)&(f<fmax+tol)))"; "end"]); end sing = [];zers = []; fmin = c*fmin, fmax = c*fmax; for i=1:m sing = [sing; %sel(roots(denh(i), "e"), fmin, fmax, tol)]; end pp = gsort(sing', "g", "i"); npp = size(pp, "*");//' // singularities just on the left of the range kinf = find(pp<fmin) if kinf <> [] then fmin = fmin+tol pp(kinf) = [] end // singularities just on the right of the range ksup = find(pp>=fmax) if ksup <> [] then fmax = fmax-tol pp(ksup) = [] end // check for nearly multiple singularities if pp <> [] then dpp = pp(2:$)-pp(1:$-1) keq = find(abs(dpp)<2*epss) if keq <> [] then pp(keq) = [], end end if pp <> [] then frqs = [fmin real(matrix([(1-epss)*pp; (1+epss)*pp], 2*size(pp, "*"), 1)') fmax] //' else frqs = [fmin fmax] end nfrq = size(frqs, "*"); // Evaluate bounds of nyquist plot //------------------------------- xt = []; Pas = [] for i=1:2:nfrq-1 w = logspace(log(frqs(i))/log(10), log(frqs(i+1))/log(10), 100); xt = [xt, w] Pas = [Pas w(2)-w(1)] end if dom == "c" then rf = freq(h("num"), h("den"), %i*xt); else rf = freq(h("num"), h("den"), exp(%i*xt)); end // xmin = min(real(rf)); xmax = max(real(rf)); ymin = min(imag(rf)); ymax = max(imag(rf)); bnds = [xmin xmax ymin ymax]; dx = max([xmax-xmin, 1]); dy = max([ymax-ymin, 1]); // Compute discretization with a step adaptation method // ---------------------------------------------------- frq = []; i = 1; nptr = nptmax; // number of unused discretization points l10last = log10(frqs($)); while i<nfrq f0 = frqs(i); fmax = frqs(i+1); while f0==fmax do i = i+2; f = frqs(i); fmax = frqs(i+1); end frq = [frq, f0]; pas = Pas(floor(i/2)+1) splitf = [splitf size(frq, "*")]; f = min(f0+pas, fmax); if dom == "c" then // Continuous case while f0<fmax rf0 = freq(h("num"), h("den"), (%i*f0)); rfc = freq(h("num"), h("den"), %i*f); // compute prediction error epsd = pas/100; // epsd = 1.d-8 rfd = (freq(h("num"), h("den"), %i*(f0+epsd))-rf0)/(epsd); rfp = rf0+pas*rfd; e = max([abs(imag(rfp-rfc))/dy; abs(real(rfp-rfc))/dx]) if e > k then rf0 = freq(h("num"), h("den"), (%i*f0)); rfc = freq(h("num"), h("den"), %i*f); // compute prediction error epsd = pas/100; // epsd = 1.d-8 rfd = (freq(h("num"), h("den"), %i*(f0+epsd))-rf0)/(epsd); rfp = rf0+pas*rfd; e = max([abs(imag(rfp-rfc))/dy; abs(real(rfp-rfc))/dx]) // compute minimum frequency logarithmic step to ensure a maximum //of nptmax points to discretize pasmin = f0*(10^((l10last-log10(f0))/(nptr+1))-1) pas = pas/2 if pas < pasmin then pas = pasmin frq = [frq, f]; nptr = max([1, nptr-1]) f0 = f; f = min(f0+pas, fmax) else f = min(f0+pas, fmax) end elseif e < k/2 then pas = 2*pas frq = [frq, f]; nptr = max([1, nptr-1]) f0 = f; f = min(f0+pas, fmax), else frq = [frq, f];nptr = max([1, nptr-1]) f0 = f; f = min(f0+pas, fmax), end end else // Discrete case pas = pas/dom while f0<fmax rf0 = freq(h("num"), h("den"), exp(%i*f0)) rfd = dom*(freq(h("num"), h("den"), exp(%i*(f0+pas/100)))-rf0)/(pas/100); rfp = rf0+pas*rfd rfc = freq(h("num"), h("den"), exp(%i*f)); e = max([abs(imag(rfp-rfc))/dy; abs(real(rfp-rfc))/dx]) if e > k then pasmin = f0*(10^((l10last-log10(f0))/(nptr+1))-1) pas = pas/2 if pas < pasmin then pas = pasmin frq = [frq, f]; nptr = max([1, nptr-1]) f0 = f; f = min(f0+pas, fmax) else f = min(f0+pas, fmax) end elseif e < k/2 then pas = 2*pas frq = [frq, f]; nptr = max([1, nptr-1]) f0 = f; f = min(f0+pas, fmax), else frq = [frq, f]; nptr = max([1, nptr-1]) f0 = f; f = min(f0+pas, fmax), end end end i = i+2 end frq(size(frq, "*")) = fmax frq = frq/c; endfunction