In chemical engineering, the production of chemicals needs to be modeled and the production process controlled. Our example will be a simple process in which the pH of a mixed solution needs to be controlled. This problem is interesting because the process is highly nonlinear and the sensor model does not have an explicit solution for the pH output. Modeling the sensor will require the use of the numerical solver fzero.
11.1 Modeling the Chemical Mixing Process
Problem
We want to model the chemical process consisting of an acid stream, a buffer stream, and a base stream that are mixed in a stirred tank.
Solution
We model the chemical equilibria by adding two reaction invariants for each inlet stream and write the dynamical equations using the invariants. These are coded in a right-hand-side function that also defines the model data structure.
How It Works
The resulting right-hand-side function, RHSpH, is shown in the following. This follows the format needed by our RungeKutta integrator (see Recipe 6.2), that is, RHS(t,x,d), with a tilde replacing the first input, as the dynamics are independent of time. Note the data structure which is defined and returned if there are no inputs. This model has quite a few parameters which are documented in the header.
The default values in the data structure are drawn from the data in the reference, with the exception of C v; this was neglected by the reference so we calculated a value for an equilibrium tank level.
11.2 Sensing the pH of the Chemical Process
Problem
The pH sensor is modeled by a nonlinear equation that cannot be solved explicitly for pH.
Solution
Use the MATLAB fzero function to solve for pH.
How It Works
The function that generates the measurement is PHSensor. Its inputs are two of the states of the system, W A4 and W B4, and the dissociation constants.
The body of PHSensor calls fzero to compute the pH. This requires an objective function that will be searched for a zero near the input point. We use a neutral pH of 7.0 as the initial condition for the optimization. We could have warm started the function by using the last value that was computed. This is a good approach if the inputs don’t change quickly. The function is vectorized for multiple input states, computing a square matrix of pH with the combinations of W a4 and W b4.
Use fzero to solve for the zero point for complex single equations. Use fminzero for sets of equations with multiple values to be found that minimized the function.
Notice that as per our usual pattern, we have defined a data structure d for passing data to the sensor model. Our two parameters are pK 1 and pK 2.
Equation 11.8 is embodied in the subfunction Fun which is passed to fzero.
We include a demo in the function as suggested in the best practices described in the style recipes. The demo specifies a range of values for the states – the invariants – based on the numbers in the reference.
The results are plotted at the end of the main function using mesh. The mesh is the default plot.
Always use the on to be certain that the commands are executed rather than toggled. Otherwise, you can get unexpected results if you have just run another script or function with those commands.
When using this function in a simulation, we need it to run as fast as possible, without any diagnostics installed for fzero. During debugging, however, you may need additional information. fzero can display information on each iteration by setting the Display option. For instance, with the 'iter' setting, it will print out information for each iteration. The updated fzero call is
and the results for a single state are
This was a very rapid solution as it is very near the starting point of 7.0. Note that fzero first found an interval containing a sign change, then searched for the zero. fzero can also output diagnostic information when complete instead of printing it during operation. For instance, if the call is
then the output structure will be available, such as
Note that the algorithm used, that is, bisection, is listed along with the total number of iterations and function evaluations. Consider a slight variation of the input state, lowering Wb4 to 4e −4 M. The number of iterations jumps significantly.
Note in particular that viewing the diagnostic information for your problem can help confirm if your tolerances are suitable. Consider the final iterations of the previous case:
The search pushed the function value all the way down to 5.4e-20, which may be more restrictive than needed. The default tolerances can be viewed by getting the default options structure using optimset.
The default tolerance on the function value, TolX, is 2.2204e-16. Note that we passed in the name of the selected optimization routine, fzero, to optimset. The same can be done with fminbnd and fminsearch.
Use optimset with the name of the optimization function to get the default options structure.
The augmented code creating the plot is shown as follows:
11.3 Controlling the Effluent pH
Problem
We want to control the pH level in the mixing tank when the flow of acid or base varies.
Solution
We will vary the base stream, i = 3, to maintain the pH. This means changing the value of q 3 using a proportional-integral controller. This will allow us to handle step disturbances.
How It Works
Despite these potential problems, this very simple controller will work for this problem for a fairly wide range of disturbances. The equilibrium value is input with a perturbation that has a proportional and integral term. The integral term uses a simpler Euler integration. The full script is described in the next recipe; here, we will call attention to the lines implementing the control.
The control variables are defined in the following. The pH set point is neutral, that is, a pH of 7. kF is the forward gain and tau is the time constant from Equation 11.10, set to 2 and 60 seconds, respectively. q3Set is the nominal set point for the base flow rate, taken from the reference.
The following code snippet shows the implementation that takes place in a loop. The error is calculated as the difference between the modeled pH measurement and the pH set point. Note the Euler integration, where intErr is updated using simply the time step times the error. Note also that we have a flag, controlIsOn, which allows us to run the script in open loop, without the control being applied.
To rigorously determine the forward gain and time constant for this problem, we would need to linearize the right-hand side for the simulation at the operating point and do a rigorous single-input-single-output control design that would involve Bode plots, root locus, and other techniques. This is beyond the scope of this book. For now, we simply select values which produce a reasonable response.
11.4 Simulating the Controlled pH Process
Problem
We want to simulate the stirred tank – mixing three streams: acid, buffer, and base – to demonstrate the control of the pH level. The base stream will be our control variable in response to perturbations in the buffer and acid streams.
Solution
We will write a script PHProcessSim with the controller starting at an equilibrium state. We will use the proportional-integral controller as derived in the previous recipe. We will structure the script to allow us to insert pulses in either or both the acid and buffer streams.
How It Works
We specify the user inputs to the script first. We are putting it into an equilibrium state and will investigate small disturbances from steady state. There is a flag, controlIsOn, for turning the control system on or off. The time step and duration are determined by iterating over a few values.
The disturbances are generated as pulses to d.q1 and d.q2. The user parameters are the size and the start/stop times of the pulses. This setup will allow us to run cases similar to the reference.
In the remainder of the script, we obtain the data structures defined in the previous recipes, specify the control parameters, and create the simulation loop. The measurements of the invariants are assumed to be exact; in practice, they need to be estimated. However, we should always test the controller under ideal conditions first, to understand its behavior without complications. The pH measurement is modeled using PHSensor from Recipe 11.2. The right-hand side for the process is defined in Recipe 11.1. Integration is performed using the RungeKutta defined in Chapter 7.
Now, we will give results for running this script with some different pulses. The nominal plot gives all three states, the measured pH, and the flow rates for the acid, base, and buffer streams. A more compact plot shows just the pH and the commanded value of q 3. We added a line in the plotting code to amend the plot title for an open loop response, so that if we run the script repeatedly, we can more easily identify the plots.
Use your control flags and string variables to customize the names of your plots.
Always do a run with the Profiler when you are implementing a numerical search or optimization routine. This gives you insight into the number of iterations used and any unsuspected bugs in your code.
In this case, there is not much optimization that can be done as most of the time is spent in fzero itself and not in our objective function, but we wouldn’t have known that without running the analysis. Whenever you are using numerical tools and have a script or function taking more than a second or two to run, analysis with Profiler is merited.
Chapter Code Listing
File | Description |
PHSensor | Model pH measurement of a mixing process |
PHProcessSim | Simulation of a pH neutralization process |
RHSpH | Dynamics of a chemical mixing process |
SensorTest | Script to test the sensor algorithm |