RAPTOR tutorial : Local linearization

In this tutorial we first simulate the time-evolution of the plasma ramp-up using a RAPTOR predictive run. From this, we extract a local linear model describing the (linear) response of the state to a small input perturbation, and compare this response to the nonlinear response of the original model.

Contents

Nominal (non-perturbed) ramp-up simulation

close all hidden;
clear; run('../RAPTOR_path.m');

[config] = RAPTOR_config; % load default config

config.echcd.params.active = true;
config.echcd.params.rdep = [0.4]; % one ECCD source at rho=0.4;
config.echcd.params.wdep = [0.35];  % wdep =0.35
config.echcd.params.cd_eff = [2];  % double current drive efficiency to see effect better.
config.echcd.params.uindices = [2]; % index of power for each actuator in input vector

config.nbhcd.params.uindices = 3; % for correct indexing of inputs

% Other modifications
config.tgrid = [0:0.001:0.1]; % time grid
config.grid.rhogrid = linspace(0,1,21); % spatial grid
config.debug.iterplot = 0; %10; % plot profiles every N iterations
config.debug.iterdisp = 10; % display progress every N iterations

% Create RAPTOR model with new parameters
[model,params,init,g,v,U] = build_RAPTOR_model(config);

% inputs
% plasma current
U(1,:)= 200e3*ones(size(params.tgrid)); % input Ip trace: ramp from 80kA to 200kA
U(1,params.tgrid<0.02) = linspace(80e3,200e3,sum(params.tgrid<0.02));
% EC actuator power: off-axis current drive, 1MW start at 40ms
U(2,:) = zeros(size(params.tgrid)); U(2,params.tgrid>0.04) = 1e6;

% initial conditions
% Plasma current
init.Ip0 = U(1,1);
% Initial condition for state
x0 = RAPTOR_initial_conditions(model,init,g(:,1),v(:,1));
% run RAPTOR
simres = RAPTOR_predictive(x0,g,v,U,model,params);
% get outputs
out = RAPTOR_out(simres,model,params);
     it  telaps newt     res   t[ms]  dt[ms]  Ip[kA] Icd[kA] Ibs[kA] Ioh[kA]      qe    qmin      q0   Vl[V] Te0[keV] Ti0[keV] ne0[e19]   f_ss  
      1   0.063    4 5.1e-10       0       1      80       0    1.41    78.6    15.4    5.59    5.59 3.4e+00    0.21    0.21    1.00 1.2e+01 
     11    0.32    2 2.6e-10      10       1     143       0    4.06     139    8.61    3.19    3.19 5.3e+00    0.40    0.40    1.00 2.0e+01 
     21    0.56    3 9.0e-13      20       1     200       0    6.24     194    6.16    2.32    2.32 4.0e+00    0.64    0.64    1.00 1.6e+01 
     31    0.79    2 1.8e-11      30       1     200       0    6.75     193    6.16    1.79    1.79 2.7e+00    0.83    0.83    1.00 1.1e+01 
     41       1    2 9.2e-13      40       1     200       0    6.67     193    6.16    1.38    1.38 2.4e+00    0.95    0.95    1.00 8.4e+00 
     51     1.3    2 2.7e-10      50       1     200    72.3    25.2     102    6.16     1.3     1.3 5.0e-01    3.20    3.20    1.00 3.2e+00 

Generate discrete-time, linear-time-varying state-space model

To generate a linear-time varying state space model, we linearize the nonlinear state equation around the nominal trajectory $(x_k^o,u_k^o)$

$0 = f(x^o_{k+1},x^o_k,u^o_k) + \frac{\partial f}{\partial x_{k+1}}\delta x_{k+1} + \frac{\partial f}{\partial x_{k}}\delta x + \frac{\partial f}{\partial u_{k}}\delta u$

or

$x_{k+1} = A_kx_k + B_ku_k$

with

$A_k = (\frac{\partial f}{\partial x_{k+1}})^{\textrm{--}1}\frac{\partial f}{\partial x_{k}}$ and $B_k = (\frac{\partial f}{\partial x_{k+1}})^{\textrm{--}1}\frac{\partial f}{\partial u_{k}}$

nt = numel(params.tgrid);
Ad = cell(1,nt); Bd = Ad; % allocate empty cells
for ik = 1:nt
    % apply scalings for numerical conditioning of inverse (same scalings
    % as in RAPTOR_predictive_step.m
   iA = out.df_dxk1{ik};
   Ad{ik} = -iA \ out.df_dxk{ik};
   Bd{ik} = -iA \ out.df_du{ik};
end
Cd = eye(size(Ad{1})); % all states as outputs
Dd = 0; % no direct feedthrough

Check response of lin vs. nonlin system: perturb ECCD power

% Perturb input
Upert = U; % copy old U
Upert(1,:) = U(1,:)+1e4*randn(size(U(2,:))); % perturb Ip with noise
Upert(2,:) = U(2,:)+1e5*rand(size(U(2,:)));  % perturb P_EC with noise

% Plot perturbed and nominal inputs
clf; subplot(211)
plot(params.tgrid,U(1,:)/1e3,'b',params.tgrid,Upert(1,:)/1e3,'k--');
title('I_p'); ylabel('[kA]'); xlabel('time [s]')

subplot(212);
plot(params.tgrid,U(2,:)/1e6,'b',params.tgrid,Upert(2,:)/1e6,'k--');
title('ECCD at \rho=0.4'); ylabel('[MW]'); xlabel('time [s]')
legend('nominal','perturbed','location','southeast');

Perturbed Nonlinear Simulation

% new nonlinear simulation
simrespert = RAPTOR_predictive(x0,g,v,Upert,model,params);
outpert=RAPTOR_out(simrespert,model,params);
     it  telaps newt     res   t[ms]  dt[ms]  Ip[kA] Icd[kA] Ibs[kA] Ioh[kA]      qe    qmin      q0   Vl[V] Te0[keV] Ti0[keV] ne0[e19]   f_ss  
      1   0.061    4 1.3e-09       0       1    80.4   0.199    1.41    78.8    15.3     5.7     5.7 3.3e+00    0.22    0.22    1.00 1.2e+01 
     11    0.38    4 3.0e-11      10       1     141   0.311    4.97     136    8.74    3.38    3.38 1.8e+00    0.46    0.46    1.00 2.9e+01 
     21    0.75    4 2.5e-11      20       1     185   0.768    7.03     178    6.64    2.48    2.48 8.6e-01    0.70    0.70    1.00 3.3e+01 
     31     1.1    3 3.7e-14      30       1     213    1.22    7.55     204    5.78     1.9     1.9 4.3e+00    0.91    0.91    1.00 1.9e+01 
     41     1.4    3 1.8e-11      40       1     197    0.24    7.05     189    6.27    1.46    1.46 2.0e+00    0.99    0.99    1.00 8.7e+00 
     51     1.7    3 2.2e-11      50       1     200    75.6    26.7    97.4    6.17    1.38    1.38 1.2e+00    3.37    3.37    1.00 1.0e+01 

Linear simulation

This takes the perturbation $\delta u_k = u_k \textrm{--} u_k^o$ and returns the state perturbation $\delta x_k = x_k \textrm{--} x_k^o$

% linear model
dU = Upert-U; % delta U
dX = zeros(size(Ad{1},2),nt); % allocate
for ik = 1:(nt-1) % run simulation
    dX(:,ik+1) = Ad{ik}*dX(:,ik) + Bd{ik}*dU(:,ik);
end
Xpertlin = Cd*dX + simres.X; % linear prediction of state (X+\delta X)


% use internal RAPTOR evaluation functions to get the correponding te and iota
iotalin = eval_iota(Xpertlin,simres.G,simres.V,model,false);
telin   = eval_te(Xpertlin,simres.G,simres.V,model,false);

Plots comparing linear and nonlinear models

clf; set(gcf,'position',[50 50 700 600])
subplot(211)
contour(out.time,out.rho,out.te/1e3,[0.2,0.5 1,2,3,4],'b'); hold on;
contour(outpert.time,outpert.rho,outpert.te/1e3,[0.2,0.5,1,2,3,4],'k','linewidth',2);
hold on;
[cs,h] = contour(out.time,out.rho,telin/1e3,[0.2,0.5,1,2,3,4],'r:','linewidth',2);
clabel(cs,h);
title('T_e profile contours'); xlabel('t'); ylabel('\rho');

hleg=legend('nominal','perturbed nonlinear','peturbed linear');
set(hleg,'location','Southeast','orient','hor')

subplot(212)
contour(out.time,out.rho,1./out.iota,[1,6/5,4/3,3/2,2,3,4],'b'); hold on;
contour(outpert.time,outpert.rho,1./outpert.iota,[1,6/5,4/3,3/2,2,3,4],'k','linewidth',2);
[cs,h] = contour(out.time,out.rho,1./iotalin,[1,6/5,4/3,3/2,2,3,4],'r-','linewidth',1);
clabel(cs,h);
title('q profile contours'); xlabel('t'); ylabel('\rho');

% end of tutorial