License Header change: Removed the LICENSE_END before beta
[scilab.git] / scilab / modules / cacsd / macros / bode.sci
1 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
2 // Copyright (C)  1985-2010 - INRIA - Serge Steer
3 // Copyright (C) 2012 - 2016 - Scilab Enterprises
4 //
5 // This file is hereby licensed under the terms of the GNU GPL v2.0,
6 // pursuant to article 5.3.4 of the CeCILL v.2.1.
7 // This file was originally licensed under the terms of the CeCILL v2.1,
8 // and continues to be available under such terms.
9 // For more information, see the COPYING file which you should have received
10 // along with this program.
11
12 function [] = bode(varargin)
13     rhs = size(varargin)
14
15     if rhs == 0 then
16         s = poly(0, "s");
17         h1 = syslin("c", (s^2+2*0.9*10*s+100)/(s^2+2*0.3*10.1*s+102.01));
18         num = 22801+4406.18*s+382.37*s^2+21.02*s^3+s^4;
19         den = 22952.25+4117.77*s+490.63*s^2+33.06*s^3+s^4;
20         h2 = syslin("c", num/den);
21
22         bode([h1; h2], 0.01, 100, ["h1"; "h2"]);
23         return;
24     end
25
26     rad = %f;
27     if type(varargin($)) == 10 then
28         if varargin($) == "rad" then
29             rad = %t;
30             rhs = rhs-1;
31             if type(varargin($-1)) == 10 then
32                 comments = varargin($-1);
33                 rhs = rhs-1;
34             else
35                 comments = [];
36             end
37         else
38             comments = varargin($);
39             rhs = rhs-1;
40         end
41     else
42         comments = [];
43     end
44     fname = "bode"; // For error messages
45     fmax = [];
46     discr = %f; // For Shannon limit
47     if or(typeof(varargin(1)) == ["state-space" "rational"]) then
48 // sys, fmin, fmax [,pas] or sys, frq
49         refdim = 1; // for error message
50         discr = varargin(1).dt<>"c";
51         if rhs == 1 then // sys
52             [frq, repf] = repfreq(varargin(1), 1d-3, 1d3);
53         elseif rhs == 2 then // sys, frq
54             if size(varargin(2), 2) < 2 then
55                 error(msprintf(_("%s: Wrong size for input argument #%d: A row vector with length>%d expected.\n"), ..
56                                fname, 2, 1))
57             end
58             [frq, repf] = repfreq(varargin(1:rhs));
59         elseif or(rhs == (3:4)) then // sys, fmin, fmax [,pas]
60             [frq, repf] = repfreq(varargin(1:rhs));
61         else
62             error(msprintf(_("%s: Wrong number of input arguments: %d to %d expected.\n"), fname, 1, 5))
63         end
64         [phi, d] = phasemag(repf);
65         if rhs >= 3 then fmax = varargin(3); end
66     elseif type(varargin(1)) == 1 then
67 // frq, db, phi [,comments] or frq, repf [,comments]
68         refdim = 2;
69         select rhs
70             case 2 then // frq,repf
71                 frq = varargin(1);
72                 if size(frq, 2) < 2 then
73                     error(msprintf(_("%s: Wrong size for input argument #%d: A row vector with length>%d expected.\n"), ..
74                                    fname, 1, 1))
75                 end
76                 if size(frq, 2) <> size(varargin(2), 2) then
77                     error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same column dimensions expected.\n"), ..
78                                    fname, 1, 2))
79                 end
80                 [phi, d] = phasemag(varargin(2));
81             case 3 then  // frq, db, phi
82                 [frq, d, phi] = varargin(1:rhs);
83                 if size(frq, 2) <> size(d, 2) then
84                     error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same column dimensions expected.\n"), ..
85                                    fname, 1, 2))
86                 end
87                 if size(frq, 2) <> size(phi, 2) then
88                     error(msprintf(_("%s: Incompatible input arguments #%d and #%d: Same column dimensions expected.\n"), ..
89                                    fname, 1, 3))
90                 end
91         else
92             error(msprintf(_("%s: Wrong number of input arguments: %d to %d expected.\n"), fname, 2, 4))
93         end
94     else
95         error(msprintf(_("%s: Wrong type for input argument #%d: Linear dynamical system or row vector of floats expected.\n"),fname,1))
96     end
97     frq = frq';
98     d = d';
99     phi = phi';
100     [n, mn] = size(d);
101
102     if comments == [] then
103         hx = 0.48;
104     else
105         if size(comments, "*") <> mn then
106             error(mprintf(_("%s: Incompatible input arguments #%d and #%d: Same number of elements expected.\n"), ...
107                           fname, refdim, rhs+1))
108         end
109         hx = 0.43;
110     end
111
112     fig = gcf();
113     immediate_drawing = fig.immediate_drawing;
114     fig.immediate_drawing = "off";
115
116     sciCurAxes = gca();
117     axes = sciCurAxes;
118     wrect = axes.axes_bounds;
119
120
121 // Magnitude
122     axes.axes_bounds = [wrect(1)+0, wrect(2)+0, wrect(3)*1.0, wrect(4)*hx*0.95];
123     axes.data_bounds = [min(frq), min(d); max(frq), max(d)];
124     axes.log_flags = "lnn";
125     axes.grid = color("lightgrey")*ones(1, 3);
126     axes.axes_visible = "on";
127     axes.clip_state = "clipgrf";
128     if size(d, 2) > 1 & size(frq, 2) == 1 then
129         xpolys(frq(:, ones(1, mn)), d, 1:mn);
130     else
131         xpolys(frq, d, 1:mn);
132     end
133 // Set datatips info
134     e = gce();
135
136     for i=1:size(e.children, "*")
137         e.children(i).display_function = "formatBodeMagTip"
138     end
139
140     if discr & fmax <> [] & max(frq) < fmax then
141         xpoly(max(frq)*[1; 1], axes.y_ticks.locations([1 $]));
142         e = gce();
143         e.foreground = 5;
144     end
145     xtitle("", _("Frequency (Hz)"), _("Magnitude (dB)"));
146
147 // Phase
148     axes = newaxes();
149     axes.axes_bounds = [wrect(1)+0, wrect(2)+wrect(4)*hx, wrect(3)*1.0, wrect(4)*hx*0.95];
150     axes.data_bounds = [min(frq), min(phi); max(frq), max(phi)];
151     axes.log_flags = "lnn";
152     axes.grid = color("lightgrey")*ones(1, 3);
153     axes.axes_visible = "on";
154     axes.clip_state = "clipgrf";
155     if size(phi, 2) > 1 & size(frq, 2) == 1 then
156         xpolys(frq(:, ones(1, mn)), phi, 1:mn);
157     else
158         xpolys(frq, phi, 1:mn);
159     end
160     ephi = gce();
161 // Set datatips info
162     for i=1:size(ephi.children, "*")
163         ephi.children(i).display_function = "formatBodePhaseTip";
164     end
165
166     if discr & fmax <> [] & max(frq) < fmax then
167         xpoly(max(frq)*[1; 1], axes.y_ticks.locations([1 $]));
168         e = gce();
169         e.foreground = 5;
170     end
171     xtitle("", _("Frequency (Hz)"), _("Phase (degree)"));
172 // Create legend
173     if comments <> [] then
174         c = captions(ephi.children, comments, "lower_caption");
175         c.background = get(gcf(), "background");
176     end
177     fig.immediate_drawing = immediate_drawing;
178 // Return to the previous scale
179     set("current_axes", sciCurAxes);
180
181     if rad == %t then
182 // This function modifies the Bode diagrams for a rad/s display instead of Hz.
183 // h is a hanlde of a figure containing Bode diagrams.
184 // Ref: http://forge.scilab.org/index.php/p/cpge/source/tree/HEAD/macros/bode_Hz2rad_2.sci
185         labels = [_("Phase (degree)"); _("Magnitude (dB)")];
186         pos_h = [9, 5];
187         for k=1:2
188             for i=1:size(fig.children(k).children, 1)
189                 if fig.children(k).children(i).type == "Compound"
190                     for j=1:size(fig.children(k).children(i).children, 1)
191                         fig.children(k).children(i).children(j).data(:, 1) = fig.children(k).children(i).children(j).data(:, 1)*2*%pi;
192                     end
193
194                     // h.children(k).title.text = h.children(k).y_label.text;
195                     xmin1 = fig.children(k).data_bounds(1)*2*%pi;
196                     xmax1 = fig.children(k).data_bounds(2)*2*%pi;
197                     ymin1 = fig.children(k).data_bounds(3);
198                     ymax1 = fig.children(k).data_bounds(4);
199
200                     rect = [xmin1, ymin1, xmax1, ymax1];
201                     nb_dec = log(xmax1/xmin1)/log(10);
202                     fig.children(k).x_label.text = _("Frequency (rad/s)");
203                     fig.children(k).x_location = "bottom";
204                     fig.children(k).y_label.text = labels(k);
205                     replot(rect, fig.children(k));
206                 end
207             end
208         end
209     end
210 endfunction