// lissajous.sq // Juan Claudio Regidor, 11/5/2002 - 21/5/2003 // Animaci—n de tiempo. 23/5/2003 // Based on sample code by Yves Piguet. title "Figuras de Lissajous" help {@ Display a Lissajous figure whose phase and frequency ratio are set with sliders. Checking the button animates time. Also, time lines (cyan on vertical and horizontal channels) can be dragged. @} variable phi // phase variable w1 // horizontal frequency variable w2 // vertical frequency variable t // time variable theta // time vector variable hor // horizontal channel amplitude vector variable vert // vertical channel amplitude vector variable x // horizontal channel amplitude value in time t variable y // vertical channel amplitude value in time t variable sc // scale variable an // animation flag variable fh // flag for horizontal function variable fv // flag for vertical function init (phi, w1, w2, t, theta, sc, an, fh, fv) = init // initialization idle (t, _idleamount) = idleAnimate(w1, w2, t, an) // idle handler make (hor, vert) = xy(theta, w1, w2, phi, fh, fv) // calculate horizontal and vertical vectors make (x, y) = xy(t, w1, w2, phi, fh, fv) // calculate horizontal and vertical values figure "Figura de Lissajous" // Lissajous figure, 'osciloscope' draw sc = drawLissajous(hor, vert, x, y, t) figure "Par‡metros" // sliders to set the phase, frequencies and draw drawParameters(phi, w1, w2, an, fh, fv) // checkmark button for animation flag mousedrag (phi, w1, w2, an, fh, fv) = dragParameters(phi, w1, w2, an, fh, fv, _id, _nb, _x1) // _nb is the slider // _nb is the slider number, or [] if // the click is not on a slider // _x1 is the current value figure "Canal Vertical" // vertical channel figure draw drawVertsin(vert, theta, y, t) mousedrag (t, _msg) = drag(t, 1, _x, _x1) mouseover _msg = overT(_id, t) figure "Canal Horizontal" // horizontal channel figure draw drawHorsin(hor, theta, x, t, sc) mousedrag (t, _msg) = drag(t, -1, _y, _y1) mouseover _msg = overT(_id, t) functions {@ function (phi, w1, w2, t, theta, sc, an, fh, fv) = init // initialization phi = 0; // phase for vertical function w1 = 1; // unit frequencies on both channels w2 = 1; t = 0; // time theta = 2 * pi * (0:360) / 360; // time vector sc = [0, 0, -1, 1]; an = 0; // don not animate fh = 2; // sin on hor. channel fv = 1; // cos on vert. channel subplots('Canal Vertical\tFigura de Lissajous\nPar‡metros\tCanal Horizontal'); function sc = drawLissajous(hor, vert, x, y, t) // Lissajous figure, 'osciloscope' line([1, 0], 0., 'h(d0d0d0)'); // draw x and y axis, light gray line([0, 1], 0., 'h(d0d0d0)'); scale('equal', [-1,1]); plot(hor, vert, 'h(00c000)'); // plot figure plot(x, y, 'xb'); // plot blue 'x' on intersection of line([1, 0], x, 'r'); // horizontal and line([0, 1], y, 'r'); // vertical values sc = scale; function drawVertsin(vert, theta, y, t) // vertical channel figure line([1, 0], 0., 'h(d0d0d0)'); // draw x and y axis, light gray line([0, 1], 0., 'h(d0d0d0)'); scale([0, 2*pi, -1, 1]); plot(theta, vert, 'h(00c000)'); // plot figure plot(t, y, 'or', 1); // plot red 'o' on intersection of line([1, 0], t, 'c', 1); // time and line([0, 1], y, 'r'); // vertical values function drawHorsin(hor, theta, x, t, sc) // horizontal channel figure line([1, 0], 0., 'h(d0d0d0)'); // draw x and y axis, light gray line([0, 1], 0., 'h(d0d0d0)'); scale([sc(1), sc(2)]); plot(hor, -theta, 'h(00c000)'); // plot figure (reversed vertical time axis) plot(x, -t, 'or', 1); // plot red 'o' on intersection of line([0, 1], -t, 'c', 1); // time and line([1, 0], x, 'r'); // horizontal values function (x, y) = xy(t, w1, w2, phi, fh, fv) // calculate horizontal and vertical values if (fh == 2) x = sin(w1 * t); else x = cos(w1 * t); end if (fv == 2) y = sin(w2 * t + phi); else y = cos(w2 * t + phi); end function drawParameters(phi, w1, w2, an, fh, fv) settabs('Frecuencia horizontal = 12 \t Coseno \tSeno '); slider(sprintf('Fase = %d grados\nFrecuencia horizontal = %d\nFrecuencia vertical = %d',... round(180*phi/pi), w1, w2), [phi; w1; w2], [0, 2*pi; 1, 12; 1, 12], '-', '', 1); button('Horizontal:\tCoseno\tSeno', fh, 'radiobutton', '', 2); button('Vertical:\tCoseno\tSeno', fv, 'radiobutton', '', 3); button(' \tAnimar tiempo', [an], 'checkmark', '', 4); function (phi, w1, w2, an, fh, fv) = dragParameters(phi, w1, w2, an, fh, fv, id, nb, x1) if isempty(id) cancel; elseif (id == 1) switch nb case 1 phi = round(90*x1/pi)*pi/90; case 2 w1 = round(x1); case 3 w2 = round(x1); end elseif (id == 2) fh = x1; elseif (id == 3) fv = x1; elseif (id == 4) an = x1; end function (t, idleamount) = idleAnimate(w1, w2, t, an) idleamount = 0.9; if (an == 1) a = clock; if (w1 > 4) || (w2 > 4) // k reduces the sweep time as a function of k = 8; // hor. and vert. frequencies elseif (w1 > 8) || (w2 > 8) k = 4; else k = 2; end // t = mod((60*a(5)+a(6))/k,2*pi); // real time is 60*minutes + seconds t = mod(t+0.16/k, 2*pi); msg = sprintf('t = %.2f', t); end function (t, msg) = drag(t, s, y, y1) if isempty(y) cancel; end t = s*round(180*y1/pi)*pi/180; if (t < 0) t = 0; end if (t > 2*pi) t = 2*pi; end msg = sprintf('t = %.2f', t); function msg = overT(id, t) if ~same(id, 1) cancel; end msg = sprintf('t = %.2f', t); @}