├── README.md ├── example.png ├── interactive1.gif ├── interactive2.gif ├── mytest1.m ├── mytest2.m ├── mytest3.m ├── mytest4.m ├── mytest5.m ├── phase_plot.m ├── phase_plot2.m ├── phase_plot_1_interactive.m └── phase_plot_2_interactive.m /README.md: -------------------------------------------------------------------------------- 1 | [![View Phase Plot with GUI for 1st and 2nd order ODE on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/62216-phase-plot-with-gui-for-1st-and-2nd-order-ode) 2 | 3 | # phase_plot 4 | With transfer function in s-domain. 5 | 6 | ``` 7 | % Phase portrait plot for SECOND and THIRD order ODE 8 | % sys is the system transfer function (in s-domain) 9 | % 10 | % intial_values is ithe initial states of th system (vector of nx1) 11 | % where n is the order of the system 12 | % 13 | % range is the minimum and the maximum boundary for the states 14 | % e.g: 3rd order system, with states: x1, x2, and x3 15 | % [x1_min x1_max; x2_min x2_max; x3_min x3_max] 16 | % 17 | % simtime is the simulation time 18 | % 19 | % scale is used to adjust the dimension of the arrows 20 | % this corresponds to the AutoScale property of the quiver function 21 | 22 | % References: 23 | % http://matlab.cheme.cmu.edu/2011/08/09/phase-portraits-of-a-system-of-odes/ 24 | ``` 25 | 26 | # phase_plot2 27 | With callback function to allow the use of nonlinear function. 28 | 29 | ``` 30 | function phase_plot2(f, intial_values, range, simtime, scale) 31 | % Phase portrait plot for a SECOND order ODE 32 | % f is the system function that will besolve using ode45, it must return 33 | % a column vector (2x1). 34 | % 35 | % intial_values is ithe initial states of th system (vector of 2x1) 36 | % 37 | % simtime is the simulation time 38 | % 39 | % scale is used to adjust the dimension of the arrows 40 | % this corresponds to the AutoScale property of the quiver function 41 | 42 | % References: 43 | % http://matlab.cheme.cmu.edu/2011/08/09/phase-portraits-of-a-system-of-odes/ 44 | ``` 45 | 46 | ![alt tag](https://github.com/auralius/phase_plot/blob/master/example.png) 47 | 48 | # phase_plot_1_interactive 49 | ![alt tag](https://github.com/auralius/phase_plot/blob/master/interactive1.gif) 50 | 51 | # phase_plot_2_interactive 52 | ![alt tag](https://github.com/auralius/phase_plot/blob/master/interactive2.gif) 53 | 54 | 55 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auralius/phase_plot/84bde4f0daa3317f39db25d355962340ad901f50/example.png -------------------------------------------------------------------------------- /interactive1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auralius/phase_plot/84bde4f0daa3317f39db25d355962340ad901f50/interactive1.gif -------------------------------------------------------------------------------- /interactive2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auralius/phase_plot/84bde4f0daa3317f39db25d355962340ad901f50/interactive2.gif -------------------------------------------------------------------------------- /mytest1.m: -------------------------------------------------------------------------------- 1 | close all; 2 | s = tf('s'); 3 | 4 | % 3rd order system 5 | figure 6 | G = 1/((s+1)*(s+1)*(s+1)); 7 | phase_plot(G, [-0.1 0 0]', [-.1 .1; -.1 .1; -.1 .1], 10) 8 | 9 | % 2nd order system 10 | figure 11 | G = 1/((s+1)*(s+2)); 12 | phase_plot(G, [-0.1 0]', [-.1 .1; -.1 .1], 10) 13 | -------------------------------------------------------------------------------- /mytest2.m: -------------------------------------------------------------------------------- 1 | function mytest2() 2 | %phase_plot2(@callback_function, initial_values, [xmin xmax; ymin ymax], simtime) 3 | phase_plot2(@f, [-8; 8], [-10 10; -10 10], 10) 4 | end 5 | 6 | %% Callback function for the ODE solver 7 | function x_dot = f(t, x) 8 | x_dot(1,1) = x(1) + 2*x(2); 9 | x_dot(2,1) = 3*x(1) + 2*x(2); 10 | end 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /mytest3.m: -------------------------------------------------------------------------------- 1 | function mytest3() 2 | close all; 3 | clear all; 4 | clc; 5 | 6 | phase_plot_2_interactive(@f, [-10 10; -10 10], 10) 7 | end 8 | 9 | %% Callback function for the ODE solver 10 | function x_dot = f(t, x) 11 | x_dot(1,1) = x(1) + 2*x(2); 12 | x_dot(2,1) = 3*x(1) + 2*x(2); 13 | end 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /mytest4.m: -------------------------------------------------------------------------------- 1 | function mytest4() 2 | close all; 3 | clear all; 4 | clc; 5 | 6 | phase_plot_2_interactive(@f, [-10 10; -10 10], 30, ... 7 | {'$\dot{x_1}=x_2$' '$\dot{x_2}=0.01*x_2^3-x_1$'}, [30 30]) 8 | end 9 | 10 | %% Callback function for the ODE solver 11 | function x_dot = f(t, x) 12 | x_dot(1,1) = x(2); 13 | x_dot(2,1) = 0.01*x(2)^3-x(1); 14 | end 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /mytest5.m: -------------------------------------------------------------------------------- 1 | function mytest() 2 | close all; 3 | clear all; 4 | clc; 5 | 6 | phase_plot_1_interactive(@f, [-4 4], 30, ... 7 | {'$\dot{x_1}=x^2-t$'}, [30 30]) 8 | end 9 | 10 | %% Callback function for the ODE solver 11 | function x_dot = f(t, x) 12 | x_dot = x^2-t; 13 | end 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /phase_plot.m: -------------------------------------------------------------------------------- 1 | function phase_plot(sys, intial_values, range, simtime, scale) 2 | % Phase portrait plot for SECOND and THIRD order ODE 3 | % sys is the system transfer function (in s-domain) 4 | % 5 | % intial_values is ithe initial states of th system (vector of nx1) 6 | % where n is the order of the system 7 | % 8 | % range is the minimum and the maximum boundary for the states 9 | % e.g: 3rd order system, with states: x1, x2, and x3 10 | % [x1_min x1_max; x2_min x2_max; x3_min x3_max] 11 | % 12 | % simtime is the simulation time 13 | % 14 | % scale is used to adjust the dimension of the arrows 15 | % this corresponds to the AutoScale property of the quiver function 16 | % 17 | % References: 18 | % http://matlab.cheme.cmu.edu/2011/08/09/phase-portraits-of-a-system-of-odes/ 19 | 20 | if nargin < 5 21 | scale = 0.5; 22 | end 23 | 24 | %% Solve the ODE 25 | [num, den] = tfdata(sys); 26 | n = length(den{:}) - 1; 27 | fprintf('System order: %i\n', n); 28 | 29 | if (n < 2 || n > 3) 30 | disp('Cannot continue...'); 31 | return 32 | end 33 | 34 | [~, x] = ode45(@f, 0:0.001:simtime, intial_values); % ode45 at 1 khz 35 | 36 | %% Vector field 37 | % 2nd order ODE 38 | if n == 2 39 | x1 = linspace(range(1, 1), range(1, 2), 10); 40 | x2 = linspace(range(2, 1), range(2, 2), 10); 41 | 42 | [X1, X2] = meshgrid(x1, x2); 43 | u = zeros(size(X1)); 44 | v = zeros(size(X2)); 45 | 46 | t = 0; 47 | for i = 1:numel(X1) 48 | X_DOT = f(t,[X1(i); X2(i)]); 49 | Vmod = sqrt(X_DOT(1)^2 + X_DOT(2)^2); 50 | u(i) = X_DOT(1)/Vmod; 51 | v(i) = X_DOT(2)/Vmod; 52 | end 53 | 54 | % Drawing 55 | h = quiver(X1, X2, u, v, 'r'); 56 | h.AutoScaleFactor = scale; 57 | axis tight equal; 58 | hold on; 59 | 60 | plot(x(:,1), x(:,2), 'b', 'LineWidth', 3); 61 | axis tight equal; 62 | xlim(range(1,:)); 63 | ylim(range(2,:)); 64 | xlabel('$x_1$', 'interpreter', 'latex') 65 | ylabel('$x_2$', 'interpreter', 'latex') 66 | hold off; 67 | 68 | % 3rd order ODE 69 | elseif n == 3 70 | x1 = linspace(range(1, 1), range(1, 2), 10); 71 | x2 = linspace(range(2, 1), range(2, 2), 10); 72 | x3 = linspace(range(3, 1), range(3, 2), 10); 73 | 74 | [X1, X2, X3] = meshgrid(x1, x2, x3); 75 | u = zeros(size(X1)); 76 | v = zeros(size(X2)); 77 | w = zeros(size(X3)); 78 | 79 | t = 0; 80 | for i = 1:numel(X1) 81 | X_DOT = f(t,[X1(i); X2(i); X3(i)]); 82 | Vmod = sqrt(X_DOT(1)^2 + X_DOT(2)^2 + X_DOT(3)^2); 83 | u(i) = X_DOT(1)/Vmod; 84 | v(i) = X_DOT(2)/Vmod; 85 | w(i) = X_DOT(3)/Vmod; 86 | end 87 | 88 | % Drawing 89 | h = quiver3(X1, X2, X3, u, v, w, 'r'); 90 | h.AutoScaleFactor = scale; 91 | hold on; 92 | 93 | plot3(x(:,1), x(:,2), x(:,3), 'b', 'LineWidth', 3); 94 | axis tight equal; 95 | xlim(range(1,:)); 96 | ylim(range(2,:)); 97 | zlim(range(3,:)); 98 | xlabel('$x_1$', 'interpreter', 'latex') 99 | ylabel('$x_2$', 'interpreter', 'latex') 100 | zlabel('$x_3$', 'interpreter', 'latex') 101 | view([1 1 1]); 102 | hold off; 103 | end 104 | 105 | fracparts=regexp(evalc('sys'),'([^\n]*)\n[ ]*-[-]+[ ]*\n([^\n]*)','tokens'); 106 | TFlatex=['$$G(s)=\frac{' fracparts{1}{1} '}{' fracparts{1}{2} '}$$']; 107 | title(TFlatex, 'interpreter','latex'); 108 | 109 | %% Callback function for the ODE solver 110 | function x_dot = f(t, x) 111 | A = tf2ss(num{:}, den{:}); 112 | x_dot = A * x; 113 | end 114 | 115 | end -------------------------------------------------------------------------------- /phase_plot2.m: -------------------------------------------------------------------------------- 1 | function phase_plot2(f, intial_values, range, simtime, scale) 2 | % Phase portrait plot for a SECOND order ODE 3 | % f is the system function that will besolve using ode45, it must return 4 | % a column vector (2x1). 5 | % 6 | % intial_values is ithe initial states of th system (vector of 2x1) 7 | % 8 | % simtime is the simulation time 9 | % 10 | % scale is used to adjust the dimension of the arrows 11 | % this corresponds to the AutoScale property of the quiver function 12 | % 13 | % References: 14 | % http://matlab.cheme.cmu.edu/2011/08/09/phase-portraits-of-a-system-of-odes/ 15 | 16 | if nargin < 5 17 | scale = 0.5; 18 | end 19 | 20 | %% Solve the ODE 21 | [~, x] = ode45(f, 0:0.001:simtime, intial_values); % ode45 at 1 khz 22 | 23 | %% Vector field 24 | % 2nd order ODE 25 | 26 | x1 = linspace(range(1, 1), range(1, 2), 10); 27 | x2 = linspace(range(2, 1), range(2, 2), 10); 28 | 29 | [X1, X2] = meshgrid(x1, x2); 30 | u = zeros(size(X1)); 31 | v = zeros(size(X2)); 32 | 33 | t = 0; 34 | for i = 1:numel(X1) 35 | X_DOT = f(t,[X1(i); X2(i)]); 36 | Vmod = sqrt(X_DOT(1)^2 + X_DOT(2)^2); 37 | u(i) = X_DOT(1)/Vmod; 38 | v(i) = X_DOT(2)/Vmod; 39 | end 40 | 41 | % Drawing 42 | h = quiver(X1, X2, u, v, 'r'); 43 | h.AutoScaleFactor = scale; 44 | hold on; 45 | plot(x(:,1), x(:,2), 'b', 'LineWidth', 3); 46 | xlabel('$x_1$', 'interpreter', 'latex') 47 | ylabel('$x_2$', 'interpreter', 'latex') 48 | axis tight equal; 49 | xlim(range(1,:)); 50 | ylim(range(2,:)); 51 | hold off; 52 | end 53 | 54 | -------------------------------------------------------------------------------- /phase_plot_1_interactive.m: -------------------------------------------------------------------------------- 1 | function phase_plot_1_interactive(f, range, simtime, figtitle, resolution, scale) 2 | % Interactive phase portrait plot for a SECOND order ODE 3 | % f is the system function that will besolve using ode45, it must return 4 | % a column vector (2x1). 5 | % 6 | % range is the limit for the x-axis ([xmin xmax]) 7 | % 8 | % simtime is the simulation time 9 | % 10 | % resolution is used to define how many arrwos will be drawn 11 | % (horizontal resolution (the time) x vertical resolution (the x-axis)) 12 | % 13 | % scale is used to adjust the dimension of the arrows 14 | % this corresponds to the AutoScale property of the quiver function 15 | % 16 | % References: 17 | % http://matlab.cheme.cmu.edu/2011/08/09/phase-portraits-of-a-system-of-odes/ 18 | 19 | if nargin < 6 20 | scale = 0.2; 21 | end 22 | 23 | if nargin < 5 24 | scale = 0.2; 25 | resolution = [simtime*2 20]; 26 | end 27 | 28 | if nargin < 4 29 | scale = 0.2; 30 | resolution = [simtime*2 20]; 31 | figtitle = ''; 32 | end 33 | 34 | set(0,'defaulttextInterpreter','latex') %latex axis labels 35 | 36 | %% Vector field 37 | t = linspace(0, simtime, resolution(1)); 38 | x = linspace(range(1), range(2), resolution(2)); 39 | 40 | dt = t(2) - t(1); 41 | 42 | [T, X] = meshgrid(t, x); 43 | u = zeros(size(T)); 44 | v = zeros(size(X)); 45 | 46 | t = 0; 47 | for i = 1:numel(X) 48 | X_DOT = f(T(i), X(i)); 49 | theta = atan(X_DOT); 50 | u(i) = cos(theta); 51 | v(i) = sin(theta); 52 | end 53 | 54 | % Drawing 55 | h = figure; 56 | hq = quiver(T, X, u, v, 'r'); 57 | hq.AutoScaleFactor = scale; 58 | hold on; 59 | xlabel('Time', 'interpreter', 'latex') 60 | ylabel('$x$', 'interpreter', 'latex') 61 | axis tight equal; 62 | xlim([0 simtime]); 63 | ylim(range); 64 | title(figtitle, 'interpreter', 'latex'); 65 | 66 | %% For current initial values 67 | while ishandle(h) 68 | try 69 | x0 = ginput(1); 70 | catch 71 | break; 72 | end 73 | 74 | [t, x] = ode45(f, x0(1):0.01:simtime, x0(2)); % ode45 at 1 khz 75 | plot(t, x, 'b', 'LineWidth', 2); 76 | plot(t(1), x(1), 'om'); 77 | 78 | if x0(1) > 0 79 | [t, x] = ode45(f, x0(1):-0.01:0, x0(2)); % ode45 at 1 khz 80 | plot(t, x, 'r', 'LineWidth', 2); 81 | end 82 | end 83 | end 84 | 85 | -------------------------------------------------------------------------------- /phase_plot_2_interactive.m: -------------------------------------------------------------------------------- 1 | function phase_plot_2_interactive(f, range, simtime, figtitle, resolution, scale) 2 | % Interactive phase portrait plot for a SECOND order ODE 3 | % f is the system function that will besolve using ode45, it must return 4 | % a column vector (2x1). 5 | % 6 | % range is the limits for the axes ([xmin xmax; ymin ymax]) 7 | % 8 | % simtime is the simulation time 9 | % 10 | % resolution is used to define how many arrwos will be drawn 11 | % (horizontal resolution (the x-axis) x vertical resolution (the y-axis)) 12 | % 13 | % scale is used to adjust the dimension of the arrows 14 | % this corresponds to the AutoScale property of the quiver function 15 | % 16 | % References: 17 | % http://matlab.cheme.cmu.edu/2011/08/09/phase-portraits-of-a-system-of-odes/ 18 | 19 | if nargin < 6 20 | scale = 0.5; 21 | end 22 | 23 | if nargin < 5 24 | scale = 0.5; 25 | resolution = [20 20]; 26 | end 27 | 28 | if nargin < 4 29 | scale = 0.5; 30 | resolution = [20 20]; 31 | figtitle = ''; 32 | end 33 | 34 | set(0,'defaulttextInterpreter','latex') %latex axis labels 35 | 36 | %% Vector field 37 | x1 = linspace(range(1, 1), range(1, 2), resolution(1)); 38 | x2 = linspace(range(2, 1), range(2, 2), resolution(2)); 39 | 40 | [X1, X2] = meshgrid(x1, x2); 41 | u = zeros(size(X1)); 42 | v = zeros(size(X2)); 43 | 44 | t = 0; 45 | for i = 1:numel(X1) 46 | X_DOT = f(t,[X1(i); X2(i)]); 47 | Vmod = sqrt(X_DOT(1)^2 + X_DOT(2)^2); 48 | u(i) = X_DOT(1)/Vmod; 49 | v(i) = X_DOT(2)/Vmod; 50 | end 51 | 52 | % Drawing 53 | h = figure; 54 | hq = quiver(X1, X2, u, v, 'r'); 55 | hq.AutoScaleFactor = scale; 56 | hold on; 57 | xlabel('$x$', 'interpreter', 'latex') 58 | ylabel('$y$', 'interpreter', 'latex') 59 | axis tight equal; 60 | xlim(range(1,:)); 61 | ylim(range(2,:)); 62 | title(figtitle, 'interpreter', 'latex'); 63 | 64 | %% For current initial values 65 | while ishandle(h) 66 | try 67 | x0 = ginput(1); 68 | catch 69 | break; 70 | end 71 | 72 | [~, x] = ode45(f, 0:0.01:simtime, x0); % ode45 at 1 khz 73 | plot(x(:,1), x(:,2), 'b', 'LineWidth', 2); 74 | plot(x(1,1), x(1,2), 'om') 75 | end 76 | end 77 | 78 | --------------------------------------------------------------------------------