[ < ] | [ > ] | [ << ] | [ 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.