%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % This program implements the direct neural controller % for the surge tank example. % % Kevin Passino % Version: 4/12/99 % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Initialize variables clear % We assume that the parameters of the tank are: abar=0.01; % Parameter characterizing tank shape (nominal value is 0.01) bbar=0.2; % Parameter characterizing tank shape (nominal value is 0.2) cbar=1; % Clogging factor representing dirty filter in pump (nominally, 1) dbar=1; % Related to diameter of output pipe g=9.8; % Gravity T=0.1; % Sampling rate beta0=0.25; % Set known lower bound on betahat beta1=0.5; % and the upper bound % Set the length of the simulation Nnc=1000; % As a reference input, we use a square wave (define one extra % point since at the last time we need the reference value at % the last time plus one) timeref=1:Nnc+1; %r(timeref)=3.25-3*square((2*pi/150)*timeref); % A square wave input r(timeref)=3.25*ones(1,Nnc+1)-3*(2*rand(1,Nnc+1)-ones(1,Nnc+1)); % A noise input ref=r(1:Nnc); % Then, use this one for plotting time=1:Nnc; time=T*time; % Next, make the vector real time % Next, set plant initial conditions h(1)=1; % Initial liquid level e(1)=r(1)-h(1); % Initial error A(1)=abs(abar*h(1)+bbar); alpha(1)=h(1)-T*dbar*sqrt(2*g*h(1))/A(1); beta(1)=T*cbar/A(1); % For the direct adaptive control case: % Note that want etadirect<=2*gammadirect/beta1 (hence if you keep gammadirect=1 % you can raise etadirect to 4) etadirect=1.25; gammadirect=1; Wu=0.01; Nu=0; epsilondirect=beta1*Wu+Nu; epsilon(1)=epsilondirect; % Define parameters of the approximator nR=100; % The number of receptive field units in the RBF thetau(:,1)=0*ones(nR,1); % Note that there are only nR "stregths" to adjust paramerrornorm(1)=0; n=2; % The number of inputs (since 1, use c(1,..) below) tempc1=0:1:9; % Defines a uniformly spaced vector roughly on the input domain % that is used to form the uniform grid on the (h,r) space % Note that 0.001 <= h <= 10 and 0.1 <= r <= 8 (notice that with this % choice there is of course some overlap on the outer regions. tempc2=0:1:9; sigma=1; % Use the same value for all % Next, form the phiu vector k=0; % Counter for centers below for i=1:10 for j=1:10 k=k+1; c(1,k)=tempc1(i); c(2,k)=tempc2(j); end end for i=1:nR phiu(i,1)=exp(-([h(1),r(1+1)]'-c(:,i))'*([h(1),r(1+1)]'-c(:,i))/sigma^2); end % Next, compute the controller input u(1)=thetau(:,1)'*phiu(:,1); % For plotting purposes we also generate the "ideal" feedback linearizing % controller output ustar(1)=(1/beta(1))*(-alpha(1)+r(1+1)); %%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Next, start the main loop: %%%%%%%%%%%%%%%%%%%%%%%%%%%%% for k=2:Nnc % Define the plant % In implementation, the input flow is restricted % by some physical contraints. So we have to put a % limit for the input flow that is chosen as 50. if u(k-1)>50 u(k-1)=50; end if u(k-1)<-50 u(k-1)=-50; end h(k)=alpha(k-1)+beta(k-1)*u(k-1); h(k)=max([0.001,h(k)]); % Constraint liquid not to go % negative % Define the controller e(k)=r(k)-h(k); % Define the deadzone size and its output: epsilon(k)=epsilondirect; if e(k)>epsilon(k) eepsilon(k)=e(k)-epsilon(k); end if abs(e(k))<=epsilon(k) eepsilon(k)=0; end if e(k)<-epsilon(k) eepsilon(k)=e(k)+epsilon(k); end % Next, perform the parameter update with the normalized gradient method: thetau(:,k)=thetau(:,k-1)+... (etadirect*phiu(:,k-1)*eepsilon(k))/(1+gammadirect*phiu(:,k-1)'*phiu(:,k-1)); % Next, for plotting, compute the norm of the parameter error paramerrornorm(k)=((thetau(:,k)-thetau(:,k-1))'*(thetau(:,k)-thetau(:,k-1))); % Next, compute the phiu vector: for i=1:nR phiu(i,k)=exp(-([h(k),r(k+1)]'-c(:,i))'*([h(k),r(k+1)]'-c(:,i))/sigma^2); end % Next, compute the controller input u(k)=thetau(:,k)'*phiu(:,k); % Define some parameters to be used in the plant A(k)=abs(abar*h(k)+bbar); alpha(k)=h(k)-T*dbar*sqrt(2*g*h(k))/A(k); beta(k)=T*cbar/A(k); % Compute the ideal controller for plotting purposes ustar(k)=(1/beta(k))*(-alpha(k)+r(k+1)); end %%%%%%%% % Plot the results figure(1) clf subplot(211) plot(time,h,'k-',time,ref,'k--') grid ylabel('Liquid height, h') title('Liquid level h and reference input r') subplot(212) plot(time,u,'k-',time,ustar,'k--') grid title('Tank input, u and the "ideal" feedback linearizing input') xlabel('Time, k') axis([min(time) max(time) -50 50]) %%%%%%%%%%%%%% figure(2) clf plot(time,paramerrornorm,'k-') grid xlabel('Time, k') title('Norm of parameter error') %%%%%%%%%%%%%% figure(3) clf plot(time,e,'k-') hold on errorbar(time,0*ones(1,length(epsilon)),epsilon,'c-') % Due to the samping period size the above will just make the deadzone % area be a cyan shaded region. grid xlabel('Time, k') title('Tracking error, e, and deadzone width') axis([min(time) max(time) min([min(e),min(-epsilon)]) max([max(e), max(epsilon)])]) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Next, compute and display the final approximator mapping and % ideal controller nonlinearity %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Request input from the user to see if they want to see the tuned % controller mapping: flag1=input('Do you want to see the nonlinear \n mapping implemented by the tuned neural \n controller? \n (type 1 for yes and 0 for no) '); if flag1==1, height=0:0.1:10; reference=0:0.1:10; for jj=1:length(height) % Define some parameters to be used in the plant At(jj)=abs(abar*height(jj)+bbar); alphat(jj)=height(jj)-T*dbar*sqrt(2*g*height(jj))/At(jj); betat(jj)=T*cbar/At(jj); for ii=1:length(reference) for i=1:nR phiut(i)=exp(-([height(jj),reference(ii)]'-c(:,i))'*([height(jj),reference(ii)]'-c(:,i))/sigma^2); end % Next, compute the controller input ut(ii,jj)=thetau(:,k)'*phiut'; % Compute the ideal controller for plotting purposes ustart(ii,jj)=(1/betat(jj))*(-alphat(jj)+reference(ii)); end end % Plot the data figure(4) clf surf(height,reference,ut); view(135,30); colormap(white); xlabel('Liquid height, h'); ylabel('Reference input, r'); zlabel('Controller output'); title('Direct neural controller mapping between inputs and output'); figure(5) clf surf(height,reference,ustart); view(135,30); colormap(white); xlabel('Liquid height, h'); ylabel('Reference input, r'); zlabel('Ideal controller output'); title('Ideal controller mapping between inputs and output'); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % End of program %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%