├── Code ├── DMDc.m ├── SEIR.m ├── constraintFCN.m ├── evaluateObjectiveFCN.m ├── main.m ├── objectiveFCN.m ├── plotFigures.m ├── poolData.m ├── poolDataLIST.m ├── prbs.m ├── rk4u.m ├── sparseGalerkinControl.m └── sparsifyDynamics.m ├── LICENSE ├── README.md └── Results ├── Results_SEIR_MPC_DMD_C0.mat ├── Results_SEIR_MPC_DMD_C1.mat ├── Results_SEIR_MPC_SINDy_C0.mat └── Results_SEIR_MPC_SINDy_C1.mat /Code/DMDc.m: -------------------------------------------------------------------------------- 1 | function [sysmodel_DMDc,U,Up] = DMDc(X,U,dt) 2 | X1 = X(:,1:end-1); 3 | X2 = X(:,2:end); 4 | numVar = size(X1,1); numOutputs = numVar; numInputs = size(U,1); 5 | Gamma = U(1:end-1); 6 | Omega = [X1; Gamma]; 7 | [U,S,V] = svd(Omega,'econ'); 8 | G = X2*V*S^(-1)*U'; 9 | [Up,Sp,Vp] = svd(X2,'econ'); 10 | Ar = G(:,1:numVar); 11 | Br = G(:,numVar+1:end); 12 | Cr = eye(numVar); 13 | sysmodel_DMDc = ss(Ar,Br,Cr,zeros(numOutputs,numInputs),dt); 14 | -------------------------------------------------------------------------------- /Code/SEIR.m: -------------------------------------------------------------------------------- 1 | function dx = SEIR(t,x,u,p) 2 | %% SEIR nonlinear dynamical system 3 | % Inputs: 4 | % t: time 5 | % x: current state 6 | % u: control input: u = beta 7 | % p: SEIRmodel parameters 8 | % 9 | % Output: 10 | % dx: time derivative of states 11 | % 12 | 13 | S = x(1); E = x(2); I = x(3); R = x(4); 14 | 15 | dx = [ -u*S*I; 16 | u*S*I - p.k*E; 17 | p.k*E - p.gamma*I; 18 | p.gamma*I]; 19 | 20 | end 21 | -------------------------------------------------------------------------------- /Code/constraintFCN.m: -------------------------------------------------------------------------------- 1 | function [c, ceq] = constraintFCN(u,x,N,p,select_model) 2 | %% Constraint function of nonlinear MPC for Lotka-Volterra system 3 | % 4 | % Inputs: 5 | % u: optimization variable, from time k to time k+N-1 6 | % x: current state at time k 7 | % N: prediction horizon 8 | % p: model parameters 9 | % 10 | % Output: 11 | % c: inequality constraints applied across prediction horizon 12 | % ceq: equality constraints (empty) 13 | % 14 | 15 | %% Nonlinear MPC design parameters 16 | % Infectious population <= zMax 17 | zMax = p.Imax; 18 | 19 | %% Integrate system 20 | if strcmp(select_model,'DMD') 21 | [xk,~] = lsim(p.sys,[u',0],[0:N].*p.Ts,x); 22 | xk = xk(2:end,:); xk = xk'; 23 | elseif strcmp(select_model,'SINDy') 24 | Ns = size(x,1); 25 | xk = zeros(Ns,N+1); xk(:,1) = x; 26 | for ct=1:N 27 | % Obtain plant state at next prediction step. 28 | xk(:,ct+1) = rk4u(@sparseGalerkinControl,xk(:,ct),u(ct),p.Ts,1,[],p); 29 | end 30 | xk = xk(:,2:N+1); 31 | end 32 | 33 | 34 | %% Inequality constraints calculation 35 | c = zeros(N,1); 36 | % Apply N population size constraints across prediction horizon, from time k+1 to k+N 37 | uk = u(1); 38 | for ct=1:N 39 | % -z + zMin < 0 % lower bound 40 | % c(ct) = -xk(2,ct)+zMin; %c(2*ct-1) 41 | % z - zMax < 0 % upper bound 42 | c(ct) = xk(3,ct)-zMax; % max infected people 43 | % update input for next step 44 | if ct DMD or SINDy 8 | % line 20: choose to run MPC with or without constraint 9 | % 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | 12 | clear all 13 | close all 14 | clc 15 | 16 | % Select DMD or SINDy model for system identification 17 | % select_model = 'DMD'; 18 | select_model = 'SINDy'; 19 | 20 | % Choose to run MPC with or without constraint 21 | constrON = 1; % Constraint on 22 | % constrON = 0; % Constraint off 23 | 24 | 25 | %% Initialize problem 26 | 27 | % Parameters of SEIR model 28 | p.beta0 = 0.5; % Transmitting rate 29 | p.gamma = 0.2; % Recovery rate 30 | p.k = 0.2; % Incubation rate 31 | 32 | % Initial conditions 33 | S0 = 0.996; % Initial susceptible population 34 | E0 = 0.002; % Initial exposed population 35 | I0 = 0.002; % Initial infected population 36 | R0 = 0; % Initial recovered population 37 | x0 = [S0, E0, I0, R0]; % Initial conditions 38 | n = 4; % Number of states (compartments) 39 | 40 | % Model specific parameters 41 | if strcmp(select_model,'DMD') 42 | dt = 1.0; % Time step 43 | elseif strcmp(select_model,'SINDy') 44 | dt = 0.01; % Time step 45 | polyorder = 3; % Library terms polynomial order 46 | usesine = 0; % Using sine functions in library 47 | end 48 | 49 | % Duration of differnt simulations 50 | T_train = 100; % Training phase, number of days 51 | T_test = 300; % Testing phase, number of days 52 | T_opt = 300; % MPC phase, number of days 53 | 54 | 55 | %% Define PRBS forcing function to excite system for model identification 56 | Nic = 2; % Number of different PRBS signals: 1 testing and 1 training 57 | taulim = [14 28]; % Update training and testing intervention each 14 to 28 days 58 | states = 0.2:0.1:1; % Interventions vary between u(t) = [0.3, 1] with 0.1 steps 59 | Nswitch = 1000; % Number of switches in prbs function 60 | rng(1,'twister'); % Control random number generator 61 | seed = randi(Nic,Nic,1); % Vary actuation in each trajectory 62 | forcing = @(x,t,seedval) p.beta0*prbs(taulim, Nswitch, states, t,0,seedval); 63 | 64 | SeedTrain = 1; % PRBS signal 1 for training 65 | SeedTest = 2; % PRBS signal 2 for testing 66 | 67 | % Define training and testing forcing u(t) 68 | tspanTrain = 0:dt:T_train; % Time span training 69 | for i = 1:length(tspanTrain) 70 | uTrain(i,:) = forcing(0,tspanTrain(i),seed(SeedTrain)); 71 | end 72 | tspanTest = 0:dt:T_test; % Time span testing 73 | for i = 1:length(tspanTest) 74 | uTest(i,:) = forcing(0,tspanTest(i),seed(SeedTest)); 75 | end 76 | 77 | 78 | %% Generate Data 79 | % Integrate forced SEIR system 80 | options = odeset('RelTol',1e-12,'AbsTol',1e-12*ones(1,n)); % Define ode options 81 | [~,xTrain]=ode45(@(t,x) SEIR(t,x,forcing(x,t,seed(SeedTrain)),p),tspanTrain,x0,options); % Integrate SEIR model using ode45 82 | 83 | % Plot SEIR training data 84 | figure; 85 | plot(tspanTrain,xTrain,'LineWidth',1.5) 86 | set(gca,'FontSize',14) 87 | title('Training data') 88 | xlabel('Time') 89 | ylabel('Population ratios (Compartments)') 90 | legend('Suscepticle','Exposed','Infected','Recovered') 91 | 92 | 93 | %% Compute true derivative 94 | eps = 0.0; % Noise level 95 | for i=1:length(xTrain) 96 | dx(i,:) = SEIR(0,xTrain(i,:),uTrain(i),p); % Run SEIR model to compute derivatives 97 | end 98 | dx(:,n+1) = 0*dx(:,n); % Add additional column of zeros for derivatives of u, needed in SINDy algorithm 99 | dx = dx + eps*randn(size(dx)); % Add measurement noise 100 | xTrain = [xTrain uTrain]; % Stack state and input measurements 101 | 102 | 103 | %% Model Identification 104 | if strcmp(select_model,'DMD') 105 | [sysmodel_DMDc,U,Up] = DMDc(xTrain(:,1:4)',uTrain',dt); % Identify DMDc model 106 | elseif strcmp(select_model,'SINDy') 107 | Theta = poolData(xTrain,(n+1),polyorder,usesine); % Generate library 108 | lambda = 1e-1; % lambda is our sparsification hyperparameter. 109 | Xi = sparsifyDynamics(Theta,dx,lambda,(n+1)); % Run SINDy using sequential treshold least squares 110 | poolDataLIST({'S','E','I','R','u'},Xi,(n+1),polyorder,usesine); % List library terms 111 | end 112 | 113 | 114 | %% Run validation 115 | % True dynamics: integrate forced true SEIR model using ode45 116 | [~,xTrueTest]=ode45(@(t,x)SEIR(t,x,forcing(x,t,seed(SeedTest)),p),tspanTest,x0,options); 117 | 118 | % DMD or SINDy dynamics 119 | if strcmp(select_model,'DMD') 120 | % DMD dynamics: integrate DMD model using linear simulation tool lsim 121 | [xModelTrain,~] = lsim(sysmodel_DMDc,uTrain,tspanTrain,x0); % Training 122 | [xModelTest,~] = lsim(sysmodel_DMDc,uTest,tspanTest,x0); % Testing 123 | elseif strcmp(select_model,'SINDy') 124 | % SINDy dynamics: integrate SINDy model using ode45 125 | % the SINDy ode with control is computed using the function sparseGalerkinControl 126 | p.ahat = Xi(:,1:n); % SINDy model terms 127 | p.polyorder = polyorder; 128 | p.usesine = usesine; 129 | [~,xModelTrain]=ode45(@(t,x)sparseGalerkinControl(t,x,forcing(x,t,seed(SeedTrain)),p),tspanTrain,x0,options); % Training 130 | [~,xModelTest]=ode45(@(t,x)sparseGalerkinControl(t,x,forcing(x,t,seed(SeedTest)),p),tspanTest,x0,options); % Testing 131 | end 132 | 133 | % Integrate unforced true SEIR dynamics for comparison 134 | [~,xUnforced]=ode45(@(t,x)SEIR(t,x,p.beta0,p),tspanTest,x0,options); 135 | 136 | % Plot model comparison 137 | clear ph 138 | figure,box on, 139 | ccolors = get(gca,'colororder'); 140 | plot(tspanTest,xTrueTest(:,1),'-','Color',ccolors(1,:),'LineWidth',1); hold on 141 | plot(tspanTest,xTrueTest(:,2),'-','Color',ccolors(2,:),'LineWidth',1); 142 | plot(tspanTest,xTrueTest(:,3),'-','Color',ccolors(3,:),'LineWidth',1); 143 | plot(tspanTest,xTrueTest(:,4),'-','Color',ccolors(4,:),'LineWidth',1); 144 | plot(tspanTest,xModelTest(:,1),'--','Color',ccolors(1,:)-[0 0.2 0.2],'LineWidth',2); 145 | plot(tspanTest,xModelTest(:,2),'--','Color',ccolors(2,:)-[0.1 0.2 0.09],'LineWidth',2); 146 | plot(tspanTest,xModelTest(:,3),'--','Color',ccolors(3,:)-[0 0.2 0.09],'LineWidth',2); 147 | plot(tspanTest,xModelTest(:,4),'--','Color',ccolors(4,:)-[0.1 0.1 0.09],'LineWidth',2); 148 | ylim([0 1]) 149 | xlabel('Time, days') 150 | ylabel('Population ratios (Compartments)') 151 | set(gca,'LineWidth',1, 'FontSize',14) 152 | title(['Comparing identified ' select_model ' vs. true dynamics']) 153 | legend('Suscepticle','Exposed','Infected','Recovered',['Suscepticle_{',select_model,'}'],['Exposed_{',select_model,'}'],['Infected_{',select_model,'}'],['Recovered_{',select_model,'}']) 154 | 155 | 156 | %% Initialize MPC 157 | Nvec = 14; % Choose prediction horizon over which the optimization is performed 158 | Imax = 0.05; % Constraint: infectious population <= zMax 159 | Ts = 1; % Sampling time 160 | Ton = 7; % Time when control starts 161 | Tcontrol = 7; % Time when control updates: once a week 162 | Duration = T_opt; % Run control for 100 time units 163 | Q = [0 0 1 0]; % State weights 164 | R = 0.1; % Control variation du weights 165 | Ru = 0.1; % Control weights 166 | x0n = x0'; % Initial condition 167 | uopt0 = p.beta0; % Set initial control input to zero 168 | 169 | % Constraints on control optimization 170 | LB = 0.3*p.beta0*ones(Nvec,1); % Lower bound of control input 171 | UB = p.beta0*ones(Nvec,1); % Upper bound of control input 172 | 173 | % Reference state, which shall be achieved: only deviation from xref1(3) (infectious cases) is penalized 174 | xref1 = [0; 0; 0; 0]; 175 | 176 | % MPC parameters used in objective and constraint function 177 | if strcmp(select_model,'DMD') 178 | pMPC.sys = sysmodel_DMDc; 179 | elseif strcmp(select_model,'SINDy') 180 | pMPC.ahat = Xi(:,1:n); 181 | pMPC.polyorder = polyorder; 182 | pMPC.usesine = usesine; 183 | end 184 | pMPC.Ts = Ts; 185 | pMPC.beta0 = p.beta0; 186 | pMPC.Imax = Imax; 187 | 188 | 189 | %% run MPC 190 | % Options for optimization routine 191 | options = optimoptions('fmincon','Display','none');%,'MaxIterations',100); 192 | 193 | % Start simulation 194 | x = x0n; % Initial state 195 | uopt = uopt0.*ones(Nvec,1); % Initial control input 196 | xHistory = x; % Stores state history 197 | uHistory = uopt(1); % Stores control history 198 | tHistory = 0; % Stores time history 199 | rHistory = xref1; % Stores reference (could be trajectory and vary with time) 200 | 201 | 202 | % For each iteration: take measurements & optimize control input & apply control input 203 | for ct = 1:(Duration/Ts) 204 | if ct*Ts>Ton % Turn control on 205 | if mod(ct*Ts,Tcontrol) == 0 % Update (Optimize) control input: once a week 206 | % Set references 207 | xref = xref1; 208 | 209 | % NMPC with full-state feedback 210 | COSTFUN = @(u) objectiveFCN(u,x,Nvec,xref,uopt(1),pMPC,diag(Q),R,Ru,select_model); % Cost function 211 | if constrON 212 | CONSFUN = @(u) constraintFCN(u,x,Nvec,pMPC,select_model); % Constraint function 213 | uopt = fmincon(COSTFUN,uopt,[],[],[],[],LB,UB,CONSFUN,options); % Optimization with constraint 214 | else 215 | uopt = fmincon(COSTFUN,uopt,[],[],[],[],LB,UB,[],options); % Optimization without constraint 216 | end 217 | end 218 | else % If control is off 219 | uopt = uopt0.*ones(Nvec,1); 220 | xref = [nan; nan; nan; nan]; 221 | end 222 | 223 | % Integrate system: Apply control & Step one timestep forward 224 | x = rk4u(@SEIR,x,uopt(1),Ts/1,1,[],p); % Runge-Kutta scheme of order 4 for control system 225 | xHistory = [xHistory x]; % Store current state 226 | uHistory = [uHistory uopt(1)]; % Store current control 227 | tHistory = [tHistory tHistory(end)+Ts/1]; % Store current time 228 | rHistory = [rHistory xref]; % Store current reference 229 | end 230 | 231 | % Evaluate objective function 232 | J = evaluateObjectiveFCN(uHistory,xHistory,rHistory,diag(Q),R,Ru,pMPC); 233 | 234 | 235 | %% Plot results 236 | 237 | % State: infectious cases I(t) 238 | figure 239 | plot(tspanTest,xUnforced(:,3),'r','LineWidth',2); hold on 240 | plot(tHistory,xHistory(3,:),'b','LineWidth',2); 241 | plot([tHistory(1),tHistory(end)],[Imax Imax],'k--','LineWidth',2); 242 | xlabel('Time') 243 | ylabel('Infectious population') 244 | set(gca,'FontSize',14) 245 | legend('No control','MPC','Constraint') 246 | 247 | % Control input u(t) 248 | figure 249 | plot(tHistory,p.beta0-uHistory,'b','LineWidth',2); 250 | xlabel('Time') 251 | ylabel('Control') 252 | set(gca,'FontSize',14) 253 | legend('Control input u(t)') 254 | 255 | % Cost J(t) 256 | figure 257 | plot(tHistory,J,'g','LineWidth',2) 258 | xlabel('Time') 259 | ylabel('Cost') 260 | set(gca,'FontSize',14) 261 | legend('Cost J(t)') 262 | 263 | 264 | 265 | %% Save results 266 | % Training 267 | Results.tTrain = tspanTrain; 268 | Results.xTrueTrain = xTrain; 269 | Results.xModelTrain = xModelTrain; 270 | Results.uTrain = uTrain; 271 | 272 | % Testing 273 | Results.tTest = tspanTest; 274 | Results.xTrueTest = xTrueTest; 275 | Results.xModelTest = xModelTest; 276 | Results.uTest = uTest; 277 | 278 | % MPC 279 | Results.t = tHistory; 280 | Results.x = xHistory; 281 | Results.u = uHistory; 282 | Results.J = J; 283 | 284 | % Unforced 285 | Results.tUnforced = tspanTest; 286 | Results.xUnforced = xUnforced; 287 | 288 | % Save 289 | save(['../Results/Results_SEIR_MPC_' select_model '_C' num2str(constrON) '.mat'],'Results') 290 | 291 | 292 | %% Plot figure 3 from tutorial paper 293 | % First, run 4 cases (DMD and SINDy with and without constraint) 294 | plotFigures 295 | 296 | -------------------------------------------------------------------------------- /Code/objectiveFCN.m: -------------------------------------------------------------------------------- 1 | function J = objectiveFCN(u,x,N,xref,u0,p,Q,R,Ru, select_model) 2 | %% Cost function of nonlinear MPC for Lotka-Volterra system 3 | % 4 | % Inputs: 5 | % u: optimization variable, from time k to time k+N-1 6 | % x: current state at time k 7 | % N: prediction horizon 8 | % xref: state references, constant from time k+1 to k+N 9 | % u0: previous controller output at time k-1 10 | % p: model parameters 11 | % Q,R,Ru: MPC cost function weights 12 | % 13 | % Output: 14 | % J: objective function cost 15 | % 16 | 17 | %% Integrate system 18 | if strcmp(select_model,'DMD') 19 | [xk,~] = lsim(p.sys,[u' 0],[0:N].*p.Ts,x); 20 | xk = xk(2:end,:); xk = xk'; 21 | elseif strcmp(select_model,'SINDy') 22 | Ns = size(x,1); 23 | xk = zeros(Ns,N+1); xk(:,1) = x; 24 | for ct=1:N 25 | % Obtain plant state at next prediction step. 26 | xk(:,ct+1) = rk4u(@sparseGalerkinControl,xk(:,ct),u(ct),p.Ts,1,[],p); 27 | end 28 | xk = xk(:,2:N+1); 29 | end 30 | 31 | %% Cost Calculation 32 | % Set initial plant states, controller output and cost 33 | uk = u(1); 34 | J = 0; 35 | % Loop through each prediction step 36 | for ct=1:N 37 | % Obtain plant state at next prediction step 38 | xk1 = xk(:,ct); 39 | % Accumulate state tracking cost from x(k+1) to x(k+N) 40 | J = J + (xk1-xref)'*Q*(xk1-xref); 41 | % Accumulate MV rate of change cost from u(k) to u(k+N-1) 42 | if ct==1 43 | J = J + (uk-u0)'*R*(uk-u0) + (p.beta0-uk)'*Ru*(p.beta0-uk); 44 | else 45 | J = J + (uk-u(ct-1))'*R*(uk-u(ct-1)) + (p.beta0-uk)'*Ru*(p.beta0-uk); 46 | end 47 | % Update uk for the next prediction step 48 | if ct=2) 23 | % poly order 2 24 | for i=1:nVars 25 | for j=i:nVars 26 | yout(:,ind) = yin(:,i).*yin(:,j); 27 | ind = ind+1; 28 | end 29 | end 30 | end 31 | 32 | if(polyorder>=3) 33 | % poly order 3 34 | for i=1:nVars 35 | for j=i:nVars 36 | for k=j:nVars 37 | yout(:,ind) = yin(:,i).*yin(:,j).*yin(:,k); 38 | ind = ind+1; 39 | end 40 | end 41 | end 42 | end 43 | 44 | if(polyorder>=4) 45 | % poly order 4 46 | for i=1:nVars 47 | for j=i:nVars 48 | for k=j:nVars 49 | for l=k:nVars 50 | yout(:,ind) = yin(:,i).*yin(:,j).*yin(:,k).*yin(:,l); 51 | ind = ind+1; 52 | end 53 | end 54 | end 55 | end 56 | end 57 | 58 | if(polyorder>=5) 59 | % poly order 5 60 | for i=1:nVars 61 | for j=i:nVars 62 | for k=j:nVars 63 | for l=k:nVars 64 | for m=l:nVars 65 | yout(:,ind) = yin(:,i).*yin(:,j).*yin(:,k).*yin(:,l).*yin(:,m); 66 | ind = ind+1; 67 | end 68 | end 69 | end 70 | end 71 | end 72 | end 73 | 74 | if(usesine) 75 | for k=1:10; 76 | yout = [yout sin(k*yin) cos(k*yin)]; 77 | end 78 | end -------------------------------------------------------------------------------- /Code/poolDataLIST.m: -------------------------------------------------------------------------------- 1 | function yout = poolDataLIST(yin,ahat,nVars,polyorder,usesine) 2 | % Copyright 2015, All Rights Reserved 3 | % Code by Steven L. Brunton 4 | % For Paper, "Discovering Governing Equations from Data: 5 | % Sparse Identification of Nonlinear Dynamical Systems" 6 | % by S. L. Brunton, J. L. Proctor, and J. N. Kutz 7 | 8 | n = size(yin,1); 9 | 10 | ind = 1; 11 | % poly order 0 12 | yout{ind,1} = ['1']; 13 | ind = ind+1; 14 | 15 | % poly order 1 16 | for i=1:nVars 17 | yout(ind,1) = yin(i); 18 | ind = ind+1; 19 | end 20 | 21 | if(polyorder>=2) 22 | % poly order 2 23 | for i=1:nVars 24 | for j=i:nVars 25 | yout{ind,1} = [yin{i},yin{j}]; 26 | ind = ind+1; 27 | end 28 | end 29 | end 30 | 31 | if(polyorder>=3) 32 | % poly order 3 33 | for i=1:nVars 34 | for j=i:nVars 35 | for k=j:nVars 36 | yout{ind,1} = [yin{i},yin{j},yin{k}]; 37 | ind = ind+1; 38 | end 39 | end 40 | end 41 | end 42 | 43 | if(polyorder>=4) 44 | % poly order 4 45 | for i=1:nVars 46 | for j=i:nVars 47 | for k=j:nVars 48 | for l=k:nVars 49 | yout{ind,1} = [yin{i},yin{j},yin{k},yin{l}]; 50 | ind = ind+1; 51 | end 52 | end 53 | end 54 | end 55 | end 56 | 57 | if(polyorder>=5) 58 | % poly order 5 59 | for i=1:nVars 60 | for j=i:nVars 61 | for k=j:nVars 62 | for l=k:nVars 63 | for m=l:nVars 64 | yout{ind,1} = [yin{i},yin{j},yin{k},yin{l},yin{m}]; 65 | ind = ind+1; 66 | end 67 | end 68 | end 69 | end 70 | end 71 | end 72 | 73 | if(usesine) 74 | for k=1:10; 75 | yout{ind,1} = ['sin(',num2str(k),'*yin)']; 76 | ind = ind + 1; 77 | yout{ind,1} = ['cos(',num2str(k),'*yin)']; 78 | ind = ind + 1; 79 | end 80 | end 81 | 82 | 83 | output = yout; 84 | newout(1) = {''}; 85 | for k=1:length(yin) 86 | newout{1,1+k} = [yin{k},'dot']; 87 | end 88 | % newout = {'','xdot','ydot','udot'}; 89 | for k=1:size(ahat,1) 90 | newout(k+1,1) = output(k); 91 | for j=1:length(yin) 92 | newout{k+1,1+j} = ahat(k,j); 93 | end 94 | end 95 | newout -------------------------------------------------------------------------------- /Code/prbs.m: -------------------------------------------------------------------------------- 1 | function u = prbs(taulim, Nswitch, states, t,Toffset,seed) 2 | if nargin==6 3 | rng(seed,'twister') 4 | 5 | else 6 | rng(0,'twister'); 7 | end 8 | 9 | tau = (taulim(2)-taulim(1))*rand(Nswitch,1) + taulim(1); 10 | tau = cumsum(tau)+Toffset; 11 | ub = states(randi(length(states),Nswitch,1)); 12 | 13 | try 14 | TF = t