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