| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Controllers compute Actuator orders. A Controller has Sensors and Observers for inputs, maintains its state, and produces orders for one or more Actuators.
| 8.1 Controller Code Structure | ||
| 8.2 Controller Example |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Like Observers, the Scilab code for Controllers is structured in four steps, two of them being initialization steps and two which are run during each control loop. These steps are:
The Setup step is where the Controller is described: the needed inputs are declared, and the produced commands, parameters, and state variables are defined.
The Init step is where the initial values are set.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Note that other examples can be found in the ‘controllers’ directory of your Odin install.
// date: 2008-JAN-22
function hrs = secToDays(tSec)
hrs = tSec/(24.*60.*60.);
endfunction
//// Computes the system state's derivative. ////
function ydot = ctr(t,y)
,
qIn = Inputs("SensorB-qIn")("value");
sIn = Inputs("SensorB-sIn")("value");
qm = Inputs("SensorA-qm")("value");
vLiq = Parameters("vLiq")("value");
k1 = Parameters("k1")("value");
k6 = Parameters("k6")("value");
d = qIn/vLiq;
ydot = -d*y+d*sIn-k1/k6*qm;
,
endfunction
function sv = doContinuousIntegration(Inputs, Parameters, StateVars),
t = secToDays(tCurr);
StateVarValue = [StateVars("sc")("value")];
sv = ode(SolverOption,StateVarValue,tLast,t,ctr);
endfunction
function sv = doDiscreteIntegration(Inputs, Parameters, StateVars),
//fill in this function
sv = 0.;
endfunction
//// Control loop entry points ////
select CtrJob,
// Set up controller data structures
case 'Setup' then
exec('./controllers/factories.sci');
// Controller global properties
CtrName = 'ctr_dcoqm';
CtrDescription = 'Dynamic controller on qIn';
SolverOption = 'adams';
continuousScheme = %t; //set to %f if integration step is to be discrete
InputsRequiredUid = ['SensorA-qm'; 'SensorB-qIn'; 'SensorB-sIn'];
Inputs = tlist([["Inputs"] ; InputsRequiredUid]);
//Note that parameters are constant
ParametersUid = ['vLiq'; 'k1'; 'k6' ; 'lambda'];
Parameters = tlist([["Parameters"] ; ParametersUid]);
//State variables (or estimated variables)
StateVarsUid = ['sc' ];
StateVars = tlist([["StateVars"] ; StateVarsUid]);
SetPointsUid = ['se'];
SetPoints = tlist([["SetPoints"] ; SetPointsUid]);
CommandsSuppliedUid = ['ActuatorA-qIn';'ActuatorA-sIn'];
Commands = tlist([["Commands"] ; CommandsSuppliedUid]);
//Initialize individual inputs
IName = "SensorA-qm";
Inputs(IName) = makeSensor();
Inputs(IName)("physicalDeviceLabel") = 'SensorA';
Inputs(IName)("physicalDeviceUid") = 'SensorA';
Inputs(IName)("deviceUid") = 'SensorA-qm';
Inputs(IName)("dataLabel") = 'qm';
Inputs(IName)("dataDescription") = 'Methane flow rate';
Inputs(IName)("unit") = 'Day^{-1}';
Inputs(IName)("domain") = [-1000; 1000];
Inputs(IName)("validityPeriod") = -1.;
Inputs(IName)("value") = 0.;
Inputs(IName)("timestamp") = 0.;
IName = "SensorB-qIn";
Inputs(IName) = makeSensor();
Inputs(IName)("physicalDeviceLabel") = 'SensorB';
Inputs(IName)("physicalDeviceUid") = 'SensorB';
Inputs(IName)("deviceUid") = 'SensorB-qIn';
Inputs(IName)("dataLabel") = 'qIn';
Inputs(IName)("dataDescription") = 'Inlet Flow';
Inputs(IName)("unit") = 'L/Day';
Inputs(IName)("domain") = [-1000; 1000];
Inputs(IName)("validityPeriod") = -1.;
Inputs(IName)("value") = 0.;
Inputs(IName)("timestamp") = 0.;
IName = "SensorB-sIn";
Inputs(IName) = makeSensor();
Inputs(IName)("physicalDeviceLabel") = 'SensorB';
Inputs(IName)("physicalDeviceUid") = 'SensorB';
Inputs(IName)("deviceUid") = 'SensorB-sIn';
Inputs(IName)("dataLabel") = 'sIn';
Inputs(IName)("dataDescription") = 'Inlet substrate concentration';
Inputs(IName)("unit") = 'g/L';
Inputs(IName)("domain") = [-1000; 1000];
Inputs(IName)("validityPeriod") = -1.;
Inputs(IName)("value") = 0.;
Inputs(IName)("timestamp") = 0.;
//Initialize individual parameters
PName = "vLiq";
Parameters(PName) = makeParameter();
Parameters(PName)("label") = 'vLiq';
Parameters(PName)("uid") = 'vLiq';
Parameters(PName)("description") = 'Bioreactor volume';
Parameters(PName)("value") = 900.;
Parameters(PName)("unit") = 'L';
PName = "k1";
Parameters(PName) = makeParameter();
Parameters(PName)("label") = 'k1';
Parameters(PName)("uid") = 'k1';
Parameters(PName)("description") = 'k1';
Parameters(PName)("value") = 1.;
Parameters(PName)("unit") = 'mmol/g';
PName = "k6";
Parameters(PName) = makeParameter();
Parameters(PName)("label") = 'k6';
Parameters(PName)("uid") = 'k6';
Parameters(PName)("description") = 'k6';
Parameters(PName)("value") = 10.;
Parameters(PName)("unit") = 'none';
PName = "lambda";
Parameters(PName) = makeParameter();
Parameters(PName)("label") = 'lambda';
Parameters(PName)("uid") = 'lambda';
Parameters(PName)("description") = 'lambda';
Parameters(PName)("value") = 1.;
Parameters(PName)("unit") = 'none';
SVName = "sc";
StateVars(SVName) = makeStateVar();
StateVars(SVName)("label") = 'sc';
StateVars(SVName)("uid") = 'sc';
StateVars(SVName)("description") = 'Substrate concentration';
StateVars(SVName)("value") = 0.;
StateVars(SVName)("unit") = 'g/L';
SPName = "se";
SetPoints(SPName) = makeSetPoint();
SetPoints(SPName)("label") = 'se';
SetPoints(SPName)("uid") = 'se';
SetPoints(SPName)("description") = 'target substrate concentration';
SetPoints(SPName)("value") = 3.2;
SetPoints(SPName)("unit") = 'g/L';
SetPoints(SPName)("physicalDeviceLabel") = 'se';
SetPoints(SPName)("physicalDeviceUid") = 'se';
SetPoints(SPName)("domain") = [-1000; 1000];
SetPoints(SPName)("validityPeriod") = -1.;
CName = "ActuatorA-qIn";
Commands(CName) = makeCommand();
Commands(CName)("physicalDeviceLabel") = 'ActuatorA';
Commands(CName)("physicalDeviceUid") = 'ActuatorA';
Commands(CName)("deviceLabel") = 'ActuatorA-pump';
Commands(CName)("deviceUid") = 'ActuatorA-qIn';
Commands(CName)("dataLabel") = 'qIn';
Commands(CName)("dataDescription") = 'Inlet flow rate command';
Commands(CName)("unit") = 'L/Day';
Commands(CName)("domain") = [-1000.; 1000.];
Commands(CName)("value") = 0.0;
Commands(CName)("timestamp") = [-1000.; 1000.];
CName = "ActuatorA-sIn";
Commands(CName) = makeCommand();
Commands(CName)("physicalDeviceLabel") = 'ActuatorA';
Commands(CName)("physicalDeviceUid") = 'ActuatorA';
Commands(CName)("deviceLabel") = 'ActuatorA-dilution';
Commands(CName)("deviceUid") = 'ActuatorA-sIn';
Commands(CName)("dataLabel") = 'sIn';
Commands(CName)("dataDescription") = 'Substrate inlet concentration command';
Commands(CName)("unit") = 'g/L';
Commands(CName)("domain") = [-1000.; 1000.];
Commands(CName)("value") = 10.;
Commands(CName)("timestamp") = [-1000.; 1000.];
,
case 'Init' then
//
tLast = secToDays(tCurr);
StateVars("sc")("value") = 0;
,
//Do not edit this step!
//Instead, edit either the 'doContinuousIntegration' or 'doDiscreteIntegration' functions
case 'Integration' then
if continuousScheme then,
y = doContinuousIntegration();
StateVars("sc")("value") = y(1);
else,
doDiscreteIntegration();
end
,
//Command Computation
case 'CommandComputation' then
vLiq = Parameters("vLiq")("value");
lambda = Parameters("lambda")("value");
k1 = Parameters("k1")("value");
k6 = Parameters("k6")("value");
se = SetPoints("se")("value");
qm = Inputs("SensorA-qm")("value");
sIn = Inputs("SensorB-sIn")("value");
sc = StateVars("sc")("value");
dint = min(max(0,(qm*k1/k6+lambda*(se-sc))/max(sIn-sc,1e-4)),10);
qInCommand = dint*vLiq;
Commands("ActuatorA-qIn")("value") = qInCommand;
Commands("ActuatorA-sIn")("value") = 15.;
tLast = secToDays(tCurr);
,
//Otherwise
else
disp('Controller Job flag unknown');
//make controller fail if the flag is unknown
//(better fail explicitly than silently)
pause;
end;
Monitoring the Bioprocess is mainly done through the Graphical User Interface (UI). Some command-line based utilities are also useful to get a peek at the system and send various commands. These can also be used to perform some automatic maintenance if needed.
| [ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Fabien Dilet on July, 22 2010 using texi2html 1.78.