简体   繁体   中英

How to speed up MATLAB integration?

I have the following code:

function [] = Solver( t )

    %pre-declaration
    foo=[1,1,1];
    fooCell = num2cell(foo);
    [q, val(q), star]=fooCell{:};

    %functions used in prosomoiwsh
    syms q val(q) star;
    qd1=symfun(90*pi/180+30*pi/180*cos(q),q);
    qd2=symfun(90*pi/180+30*pi/180*sin(q),q);
    p1=symfun(79*pi/180*exp(-1.25*q)+pi/180,q);
    p2=symfun(79*pi/180*exp(-1.25*q)+pi/180,q);
    e1=symfun(val-qd1,q);
    e2=symfun(val-qd2,q);
    T1=symfun(log(-(1+star)/star),star);
    T2=symfun(log(star/(1-star)),star);

    %anonymous function handles
    lambda=[0.75;10.494441313222076];
    calcEVR_handles={@(t,x)[double(subs(diff(subs(T1,star,e1/p1),q)+subs(lambda(1)*T1,star,e1/p1),{diff(val,q);val;q},{x(2);x(1);t})),double(subs(diff(subs(T1,star,e1/p1),q)+subs(lambda(1)*T1,star,e1/p1),{diff(val,q);val;q},{0;x(1);t})),double(subs(double(subs(subs(diff(T1,star),star,e1/p1),{val;q},{x(1);t}))/p1,q,t))];@(t,x)[double(subs(diff(subs(T2,star,e2/p2),q)+subs(lambda(2)*T2,star,e2/p2),{diff(val,q);val;q},{x(4);x(3);t})),double(subs(diff(subs(T2,star,e2/p2),q)+subs(lambda(2)*T2,star,e2/p2),{diff(val,q);val;q},{0;x(3);t})),double(subs(double(subs(subs(diff(T2,star),star,e2/p2),{val;q},{x(3);t}))/p2,q,t))]};

    options = odeset('AbsTol',1e-1,'RelTol',1e-1);
    [T,x_r] = ode23(@prosomoiwsh,[0 t],[80*pi/180;0;130*pi/180;0;2.4943180186983711;11.216948999754299],options);

    save newresult T x_r

    function dx_th = prosomoiwsh(t,x_th)
        %declarations
        k=0.80773938740480955;
        nf=6.2860930902603602;
        hGa=0.16727117784664769;
        hGb=0.010886618389781832;
        dD=0.14062935253218495;
        s=0.64963817519705203;
        IwF={[4.5453398382686956 5.2541234145178066 -6.5853972592002235 7.695225990702979];[-4.4358339284697337 -8.1138542053372298 -8.2698210582548395 3.9739729629084071]};
        IwG={[5.7098975358444752 4.2470526600975802 -0.83412489434697168 0.53829395964565041] [1.8689492167233894 -0.0015017513794517434 8.8666804106266461 -1.0775021663921467];[6.9513235639494155 -0.8133752392893685 7.4032432556804162 3.1496138243338709] [5.8037182454981568 2.0933267947187457 4.852362963697928 -0.10745559204132382]};
        IbF={-1.2165533594615545;7.9215291787744917};
        IbG={2.8425752327892844 2.5931576770598168;9.4789237295474873 7.9378928037841252};
        p=2;
        m=2;
        signG=1;
        n_vals=[2;2];
        nFixedStates=4;
        gamma_nn=[0.31559428834175318;9.2037894041383641];
        th_star_guess=[2.4943180186983711;11.216948999754299];

        %solution
        x  = x_th(1:nFixedStates);
        th = x_th(nFixedStates+1:nFixedStates+p);

        f  = zeros(m,1);
        G  = zeros(m,m);
        ZF = zeros(p,m);
        ZG = zeros(p,m,m);

        for i=1:m
            [f(i), ZF(:,i)] = calculate_neural_output(x, IwF{i}, IbF{i}, th);
            for j=1:m
                [G(i,j), ZG(:,i,j)] = calculate_neural_output(x, IwG{i,j}, IbG{i,j}, th);
            end
        end

        detG = det(G);
        if m == 1
            adjG = 1;
        else
            adjG = detG*G^-1;
        end

        E = zeros(m,1);
        V = zeros(m,1);
        R = zeros(m,m);

        for i=1:m
            EVR=calcEVR_handles{i}(t,x);
            E(i)=EVR(1);
            V(i)=EVR(2);
            R(i,i)=EVR(3);
        end


        Rinv     = R^-1;
        prod_R_E = R*E;
        ub = f + Rinv * (V + k*E) + nf*prod_R_E;
        ua = - detG / (detG^2+dD) * (adjG * ub) ;
        u  = ua - signG * (hGa*(ua'*ua) + hGb*(ub'*ub)) * prod_R_E;

        dx_th = zeros(nFixedStates+p, 1); %preallocation

        %System in form (1) of the IEEE paper
        [vec_sys_f, vec_sys_G] = sys_f_G(x);
        dx_nm  = vec_sys_f + vec_sys_G*u;

        %Calculation of dx
        index_start = 1;
        index_end   = -1;
        for i=1:m
            index_end   = index_end + n_vals(i);
            for j=index_start:index_end
                dx_th(j) = x(j+1);
            end
            dx_th(index_end+1) = dx_nm(i);
            index_start = index_end + 2;
        end

        %Calculation of dth

        AFvalueT = zeros(p,m);
        for i=1:m
            AFvalueT(:,i) = 0;
            for j=1:m
                AFvalueT(:,i) = AFvalueT(:,i)+ZG(:,i,j)*ua(j);
            end
        end

        dx_th(nFixedStates+1:nFixedStates+p) = diag(gamma_nn)*( (ZF+AFvalueT)*prod_R_E -s*(th-th_star_guess) );
        display(t)
    end

    function [y, Z] = calculate_neural_output(input, Iw, Ib, state)
        Z = [tanh(Iw*input+Ib);1];
        y = state' * Z;
    end

    function [ f,g ] = sys_f_G( x )
        Iz1=0.96;
        Iz2=0.81;
        m1=3.2;
        m2=2.0;
        l1=0.5;
        l2=0.4;
        g=9.81;
        q1=x(1);
        q2=x(3);
        q1dot=x(2);
        q2dot=x(4);
        M=[Iz1+Iz2+m1*l1^2/4+m2*(l1^2+l2^2/4+l1*l2*cos(q2)),Iz2+m2*(l2^2/4+l1*l2*cos(q2)/2);Iz2+m2*(l2^2/4+l1*l2*cos(q2)/2),Iz2+m2*l2^2/4];
        c=0.5*m2*l1*l2*sin(q2);
        C=[-c*q2dot,-c*(q1dot+q2dot);c*q1dot,0];
        G=[0.5*m1*g*l1*cos(q1)+m2*g*(l1*cos(q1)+0.5*l2*cos(q1+q2));0.5*m2*g*l2*cos(q1+q2)];
        f=-M\(C*[q1dot;q2dot]+G);
        g=inv(M);
    end


end

Its target is to simulate the control of a 2-DOF robotic arm using a certain control law. The results I get after running the simulation are correct(I have a graph of the output I should expect), but it takes ages to finish!

Is there anything I could do to speed up the process?

In order to improve the computational speed of any integration in Matlab, a few options are available to you:

  1. Reduce the required accuracy (which you already have done)
  2. Use an adapted integrator. As mentioned by @sanchises, sometimes ode23 can be longer than another ode solver in Matlab (if your equation is stiff for instance). You could try to determine which solver is most adapted from the documentation... Or simply try them all!
  3. The best solution, but by far the most time consuming, would be to use a compiled language, such as C or Fortran. If the integration is but a part of your Matlab program, you could use Mex files , and translate only the integration to a compiled language. You could also create dynamic libraries in your compiled language and load them in Matlab using loadlibrary . I use loadlibrary and an integration routine written in Fortran for the integration of orbits and trajectories, and I get over 100 times speedup with Fortran vs. Matlab! Of course, technically, the integration is not in Matlab anymore... But the library or Mex files trick allows you to only convert the integration part of your program to a different language! A number of open source integrators are available, such as ODEPACK or RKSUITE in Fortran. Then, you only need to create a wrapper and your dynamics function in the correct language.

So to put it in a nutshell, if you're going to use this integration a lot, I would advise using a compiled language. If not, you should make do with Matlab, and be patient!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM