Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
780 views
in Technique[技术] by (71.8m points)

octave - callback function throws unexpected "nonconformant arguments" error

I'm using GNU Octave, version 4.4.1. I'm trying to make an interactive plot of a simple oscillator by including two sliders which would allow the initial velocity and oscillator mass to be changed. The plot itself shows fine, as well as the script with one slider (for velocity). Here's a part of that script with the callback function:

function titranje_ia1 (hslider, event)

v0 = get ( hslider, "value" );
m = 1;
k = 1;
t = 0:0.1:30;
x = v0*sin(sqrt(k/m)*t);
axes ('position', [0.1, 0.2, 0.8, 0.75]);
h = plot ( t, x );
axis ([0 30 -11 11]);
set (h, "linewidth", 2);
set (gca, "xlabel", "t (s)", "ylabel", "x (m)", "fontsize", 12);
set (gca, 'XTick', 0:pi:10*pi)
set (gca, 'XTickLabel', {'0','pi','2pi','3pi','4pi','5pi','6pi','7pi','8pi','9pi','10pi'})
grid on;
l = legend (sprintf('v0 = %f', v0));
set (l, "fontsize", 12)

endfunction

However, when I include a second slider

function titranje_ia2 (hslider1, hslider2, event)

v0 = get ( hslider1, "value" );
m = get ( hslider2, "value" );
k = 1;
t = 0:0.1:30;
x = v0.*sin(sqrt(k./m).*t);
axes ('position', [0.1, 0.2, 0.8, 0.75]);
h = plot ( t, x );
axis ([0 30 -11 11]);
set (h, "linewidth", 2);
set (gca, "xlabel", "t (s)", "ylabel", "x (m)", "fontsize", 12);
set (gca, 'XTick', 0:pi:10*pi)
set (gca, 'XTickLabel', {'0','pi','2pi','3pi','4pi','5pi','6pi','7pi','8pi','9pi','10pi'})
grid on;
l = legend (sprintf('v0 = %f', v0));
set (l, "fontsize", 12)

endfunction

I receive an error:

error: titranje_ia2: product: nonconformant arguments (op1 is 0x0, op2 is 1x301) execution error in graphics callback function

Since I know that 'k' is a scalar and 't' a vector (but I'm not sure what v0 and m would be; I suppose scalars), I included an elementwise operations in function 'x' definition. 't' size is 1x301, so I assume that 'sqrt(k./m)' is 0x0 (as seen by Octave). Shouldn't it be 1x1? Indeed, when I try

size(m)

I receive ans = 0 0 (for size(v0) I get ans = 1 1). Could it be that there is a problem with slider definition? I include at the end both slider definitions:

%Definiramo ui element: 'klizac' za v0
hslider1 = uicontrol (
"style", "slider",
"units", "normalized",
"position", [0.1, 0.0, 0.8, 0.1],
"min", 1,
"max", 10,
"value", 4,
"callback", @titranje_ia2
);

%Definiramo ui element: 'klizac' za m
hslider2 = uicontrol (
"style", "slider",
"units", "normalized",
"position", [0.1, 0.05, 0.8, 0.1],
"min", 1,
"max", 10,
"value", 1,
"callback", @titranje_ia2
);

Thank You in advance! Best regards,

Igor


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You seem to be misunderstanding a bit how callbacks work. Whenever you interact with a uicontrol object, the associated callback is always called automatically with [at least] two arguments: the first is always the 'handle' of the corresponding uicontrol object that triggerred he callback, and the second is the type of 'event' that was triggered. Therefore your callback function needs to always have a signature of callbackname( hndl, evt ) at the very least, so that it can handle those two arguments passed to it by default.

You can specify extra arguments to passed to the callback if you want, but these will necessarily be interpreted as 3rd, 4th, and so on, inside the callback function (see example below).

If you have a case like yours where you don't really care where the event originated from, and you want to affect (or in this case 'read from') two existing uicontrols in a single callback, regardless which one triggerred the event, the simplest thing to do is to make both slider handles to be extra arguments to the callback, and simply ignore the first argument (i.e. the 'active handle') inside your callback. (in fact, you're already ignoring the 'event' argument too!).

Here's an example:

%% In file makesliders.m
function makesliders()
  % Label and slider for initial velocity
    IV_label  = uicontrol( 'style', 'text'  , 'units', 'normalized', 'position', [0.10, 0.025, 0.30, 0.075], 'string', 'Initial Velocity' );
    IV_slider = uicontrol( 'style', 'slider', 'units', 'normalized', 'position', [0.45, 0.025, 0.50, 0.075], 'min', 1, 'max', 10 );

  % Label and slider for oscillator mass
    OM_label  = uicontrol( 'style', 'text'  , 'units', 'normalized', 'position', [0.10, 0.125, 0.30, 0.075], 'string', 'Oscillator Mass ' );
    OM_slider = uicontrol( 'style', 'slider', 'units', 'normalized', 'position', [0.45, 0.125, 0.50, 0.075], 'min', 1, 'max', 10 );

  % Set callbacks and initial values to IV and OM sliders, and plot initial graph
    v0_init = 4;   m_init = 1;
    set( IV_slider, 'value', v0_init, 'callback', { @slider_callback, IV_slider, OM_slider } );
    set( OM_slider, 'value', m_init , 'callback', { @slider_callback, IV_slider, OM_slider } );
    plot_oscillation( v0_init, m_init );
endfunction

function slider_callback (active_handle, event, IV_slider, OM_slider )
    v0 = get( IV_slider, 'value' );
    m  = get( OM_slider, 'value' );
    plot_oscillation( v0, m );
endfunction

function plot_oscillation( v0, m )
    k  = 1;
    t  = 0 : 0.1 : 30;
    x = v0 * sin( sqrt( k / m ) * t );

    h = plot( t, x );   set( h  , 'linewidth', 2);
    set( gca, 'position', [0.1, 0.325, 0.85, 0.650], 'xlim', [0, 30], 'ylim', [-11, 11], 'xlabel', 't (s)', 'ylabel', 'x (m)', 'fontsize', 12, 'xtick', [0 : pi : 10 * pi], 'xticklabel', strcat( arrayfun( @num2str, 0:10, 'uniformoutput', false ), 'pi' ), 'xgrid', 'on', 'ygrid', 'on' );
    l = legend( sprintf( 'v0 = %.2f, m = %.2f', v0, m ) );   set( l, 'fontsize', 12 );
endfunction
image

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...