same
You do if the plant model has an integrator in the transfer function. Kp is
a slope for this type. You can use any delta time you want. The slope will
be constant. If you want to to know more, look at the book titled: "Process
Control Fundamentals for the Pulp & Paper Industry" published by TAPPI. I
wrote Chapter 7: Controller Tuning Methods. This method of tuning level
control is discussed thoroughly including simulation results.

On Apr 11, 8:33 am, "Fred Thomasson" <fthomasson at comcast.net>
wrote:

Yes, I see. When you used Ki and Kp together I think in terms of
motion control gains here Kp is the proportional gain, not a plant
gain, and Ki is the integrator gain not a time constant.
It would have been clearer if you said you were dealing in seconds,
that would have explained the 15, and used Ti instead of Ki like we
were.
OK, we are on the same page now.

I have been playing around with level control tuning optimisation
using Scilab. What I have come up with is a draft Scilab program that
will find the optimum PID settings to minimise a cost function with
configurable weighting coefficients so that you can specify the
relative importance of:
a) Max level error on inflow disturbance
b) Sum of error
c) Small valve movements
all on an inflow disturbance. (I should really add setpoint responses
too)
Please note that I haven't properly tested it, there are most probably
bugs in.
The using of integral gain instead if time constant is because you get
better optimiser performance like that.
To use it, copy from below the "level Optimse.sce" and "level.sci"
into two separate files and change the Scilab directory to there and
then "exec" the "level Optimse.sce" from the menu in Scilab. It will
then prompt you for values and return the optimised tuning
coefficients.
Regards
Pieter Steenekamp
*************************************************
* Fiirst the "level Optimise.sce" program *
*************************************************
// This program finds the PID settings to optimise the response
// on a level controller with significant dead time in the actuator
// it uses the SciLab functions "NDcost" and "optim"
// to do the optimisation
clear;
plotON=0;
exec('level.sci')
Thold=evstr(x_dialog('Tank holdup in seconds ?','50'));
Tpdt =evstr(x_dialog('actuator dead time ?','10'));
maxErrorWeight=evstr(x_dialog('maxErrorWeight ?','10'));
sumAbsErrorWeight=evstr(x_dialog('sumAbsErrorWeight ?','1'));
sumDeltaCoSquaredWeight=evstr(x_dialog('sumDeltaCoSquaredWeight ?','1'));
// initial tuning values:
x(1)= -1; // for proportional gain
x(2)= 0; // for integral gain
x(3)= 0; // for derivative gain
printf(' Maybe now is a good time to have coffee, because this optim-
function is sometimes slow \n');
[f,xopt,gopt]=optim(list(NDcost,level),x)
Kc=xopt(1)
Ki=xopt(2)
Kd=xopt(3)
plotON=1;
g=level(xopt);
*************************************************
* Now for the "level.sci" function *
*************************************************
function f = level(x)
// The basic intent of this function is to be called by "optim" from
outside of this to find the optimum x
// This fuction calculates the optimisation cost function as a
function of Kc, Ki & Td, supplied as vector x
// Thold, Tpdt,
plotON,maxErrorWeight,sumAbsErrorWeight,sumDeltaCoSquaredWeight must
be global variables, declared outside
// The approach on units taken is to work in percent of range and not
in engineering units
// Optimisation variables:
max_error = 0;
sumAbsError=0;
sumDeltaCoSquared=0; // To penalise fast cahnges in controller
output
// Read tuning variables x
Kc=x(1);
Ki=x(2);
Kd=x(3);
T=1; // simulation update period in seconds
Kp = -T/Thold; // Tank gain - take it as negative because
control on outflow
PV(1)=0; // fluid level in meters
CO(1)=0; // Control output in percent of full
output
ui(1) = 0; // integrator contribution to CO
up(1) = 0; // proportional contribution to CO
ud(1) = 0; // derivative contribution to CO
flow_out(1)=0; // flow pumped out in cubic meters per
minute
flow_in = 10;
new_error=0; // error in level meter
old_error=0; // error in level meter
max_time = 200; // length of simulation in seconds
N=round(max_time/T); // convert to sample periods
// intialise dead time buffer
if Tpdt>0 then
for j = 1:Tpdt,
opBuffer(j) = 0;
end
end
for n=1:N;
t(n) = n*T; // Compute time indexes. This is needed
for time index
SP(n)=0;
// calculate the new flow, as a function of controller output and dead
time:
if Tpdt > 0 then
flow_out(n+1) = opBuffer(Tpdt) ; //pure dead time is applied to
out floe
else
flow_out(n+1) = CO(n);
end
// update dead time buffer
if Tpdt>1 then
for j = 0:Tpdt-2,
j1 = Tpdt - j;
opBuffer(j1) = opBuffer(j1-1);
end
end
opBuffer(1) = CO(n);
// Integrate the difference between the flow in and flow out.
PV(n+1) = PV(n) + Kp*(flow_in - flow_out(n))*T;
if PV(n+1) > 100 then
PV(n+1)0
elseif PV(n+1)<-100 then
PV(n+1) = -100
end
// Calculate the control output using a simple PID
old_error = new_error(n); // shift the error history. this is
necessary for the differentiator
new_error(n+1) = SP(n)-PV(n); // calculate error
if abs(new_error(n+1)) > max_error then
max_error = abs(new_error(n+1));
end
sumAbsError = sumAbsError + abs(new_error(n+1));
up(n+1) = Kc*new_error(n+1); // calculate the proportional control
output percent
ui(n+1) = ui(n) + Ki*new_error(n+1); // calculate the integrator
control output percent
if ui(n+1) > 100 then
ui(n+1)0
elseif ui(n+1)<-100 then
ui(n+1) = -100
end
ud(n+1) = Kd*(new_error(n+1)-old_error); // calculate the derivative
control output percent
CO(n+1) = ui(n+1) + up(n+1) + ud(n+1); // The control output
is the sum of the integrator and proportional terms
sumDeltaCoSquared = sumDeltaCoSquared + (CO(n+1) - CO(n))*(CO(n+1) -
CO(n));
if CO(n+1) > 100 then
CO(n+1)0
elseif CO(n+1)<-100 then
CO(n+1) = -100
end
end
if plotON > 0.5 then
subplot(2,1,1); // Level on top
plot(PV);
xtitle('Level');
legend("level");
subplot(2,1,2); // Control output at bottom
plot(CO);
xtitle('Control Output');
legend("CO");
end
f = maxErrorWeight*max_error + sumAbsErrorWeight*sumAbsError +
sumDeltaCoSquaredWeight*sumDeltaCoSquared;
endfunction

This is very good. I would have started a new thread because this is
actually more related to the iterative tuning thread than the level
control thread.
I have used lqrsolve but not optim. I will have to see if there is a
difference. From what I have seen evaluation function for qrsolve
returns a vector of errors that lqrsolve uses to calculate the gradient
of the error function as a function of the change in gains. It looks
like optim only requires the evaluation function only return an error
value. I doubt the optim can be as smart about how it changes the gains
as the lqrsolve. This may result in more iterations because the gradient
may not be calculated. I think this point is VERY important because it
is critical that the number of iterations be minimized.
Do you mind if I put this on my FTP site in the NG directory and update
it as you update your files?
I can see you added a dead time to the model. That will make things
interesting but very general.
Peter Nachtwey

I concur. Another reason why the choice of solver is important is to
ensure you do find the global optimum. I haven't tried lqrsolve, but
found Matlab's Optimisation and Genetic Algorithm Toolboxes to be
significantly better than Scilab's optim; both in terms of speed and
ability to find "difficult" global optimums.

I am very happy to confirm that, yes it is true that, if you start a
level from steady with level at required value, then the input floe
changes, and you are not concerned about the level coming back fast,
it is better to use only proportional control. That is because I have
been doing it for years with good success, and just confirmed it using
different models. I normally do add at least a very tiny bit of
integral control; maybe use an integral time constant of 1000 times
the time it would take the tank to empty from full with no in-flow and
maximum controller output. In really difficult cases, when the
"actuator" behaves like it has significant dead time, I have been
forced to use even longer integral time constants to achieve
acceptable response. (I use inverted commas, because it is mostly the
process arrangements causing this apparent dead time and not directly
the actuator, but for modeling purposes you can just as well model it
as though the actuator is sluggish)
I followed this thread and did do testing, and found, yes indeed, the
simulations confirm my experience. If you have a difficult level
control, prone to level reaching high and/or low limits, and you are
not worried with other things, like changing the controller output
fast, or the level actually at SP, then indeed if you use less
integral control you can then use stronger proportional control
without level going unstable, and this will give you less risk of
level tripping on low or high limit. Especially if an increase in-flow
is not normally followed shortly by another increase in in-flow. This
will make it that if you "caught" the level from violating the limit
with proportional control, very weak integral action is sufficient to
bring to back to SP very slowly.
I read Mr. Peter Nachtway concerns that they did not use his program
so I check. So I see Mr. Peter Nachtway's program does not model the
issue at hand. So I said, no problem it is very easy to make very
small change so that the program of Mr. Peter Nachtway does indeed
model the issue at hand. I was very careful not to change the other
things that he said Mr. Pieter Steenekanp changed. Please look below
for the program after I made the changes.
Please note Mr. Peter Nachtway, I did not use Mr Pieter Steenekanps
program. I copied the one in the reference you gave in the thread and
modified it, using absolutely minimum modifications, just to test the
response from steady state when the in-flow changes. Please don't get
mad at me too! I am already shit scared to write this posting, but I
think I owe it to the other people to share my experience and testing
results using your program.
So I also download Scilab. This is a very nice package. I then also
build other models using the Scicos application in Scilab to test this
statement and found it to be generally true. There might be some
strange combinations or conditions that makes it untrue, but
consistent with my doing it practically and testing many, including
Mr. Peter Nachtway's (see below) models, I am very confident that it
is true and valid and a good practical tuning method.
Of course, in Mr Peter Nachtway's this model - do not interpret the
tank level as the actual level, consider it to be the changes from
steady state. You can change the program of course to reflect actual
level, but when Mr. Pieter Steenekanp did that, Mr Peter Nachtway got
mad, so I rather make minimum changes to Mr. Peter Nachtway's program.
I don't like it when Mr. Peter Nachtway get mad.
But on the other hand, this proportional-only control using a gain of
-9200 is indeed very strong, with a strong under-damped, but still not
unstable, behavior. So I reduced the proportional gain, but the
maximum level is still smaller than if you have any integral control.
But on the other hand, this model is "very kind" to some difficult
tank level controls in the chemical industry. So I build a Scicos
model of tank level control, but instead of the pump having just a
single lag, I added two more lags, also including some dead time, to
make the closed loop control "not so very kind". And I changed the
coefficients to try to duplicate the problem that Mr. John Jay
described. With Mr Peter Nachtway's model coefficients you will very
easily prevent a low level trip. So there must be some other
combination of model parameters replicating this problem. So I found
this by adding apparent dead time to the "actuator" and made the tank
surface area smaller.
And indeed, I also find that for "not so very kind" applications, if
the tank is prone to empty on an in-flow disturbance, and if there is
a more sluggish response (like in 3 lags in series, or dead time)
included, the conclusion is not only valid, but it translates to very
practical way of tuning the level control. Although it is true for Mr.
Peter Nachtway's coefficients, this represents a "very kind" level
control and it does not really make much of a difference. Although the
statement is true, it does not translate to practical advice unless
you start with a level control that is difficult to tune to prevent
level trips.
Please Mr Peter Nachtway, don't get mad. Just give us a model to show
us that we are wrong. Don't say we must read your thread, because your
thread is very helpful for another application, not this one. Just
show us your model, representing a level control starting from steady
state, with the level at SP. Then test the response on a change in in-
flow. Then you try it out with your PI control, and then also with the
P-only control giving the smallest level deviation. If you find that
PI-control does better, try to increase the gain of the P-only
control, until you get to the point where it goes unstable and does
indeed not decrease the maximum level deviation further. If you find
the biggest gain for the proportional-only controller so that if you
increase the gain further, the maximum level deviation increases, and
this maximum gain for the proportional-only control gives a maximum
level deviation that is larger than the maximum level deviation of
your PI-controller with non-negative integral control action, then you
will have proofed your point. If you achieve that I would say: well
done Mr. Peter Nachtway, you taught me something very useful, thank
you very much. And I will go and find where did I go wrong.
Thank you very much
Lu Hing
// Mr. Peter Nachtway's program with very small modifications by Mr.
Lu Hing
// to represent the case where you start from steady state
// with level at required value and there is a change in in-flow.
// TANK LEVEL CONTROL
maximumLevel=0; // added by Mr. Lu Hing to check the maximum level
Kp=-0.2368; // pump gain. (m^3/m)/CO%
Tp=1/12; // plump time constant. minutes
Kt=0.0279; // 1/(tank surface area) 1/m^2
Tc=0.25; // closed loop time constant. minutes
Tc=0.1; // closed loop time constant. minutes
Kc=-605.444; // controller Gain. percent output per meter of error
Ti=3*Tc; // integrator time constant minutes
// For Mr. Peter Nachtway's tuning keep the following commented out,
to test proportional only, delete the comment signs
// Ti = 1000000 // added by Mr. Lu Hing to practically remove
integral so to check proportional control only
// Kc = -9200 // added by Mr. Lu Hing to check strong
proportional control
T=1/120; // simulation update period minutes
PV(1)=0; // fluid level meters
CO(1)=0; // control output. percent of full output
ui(1) = 0; // integrator contribution to CO
flow_in ; // flow in. m^3/min
flow_out(1)=0; // flow pumped out. m^3/min
N=round(10/T); // CONVERT TO SAMPLE TIMES
for n=1:N; // simulate 10 minutes
SP(n)=2; // set point meters
SP(n)=0; // added by Mr. Lu Hing to check max level on inflow
disturbance from steady state and not from SP change
// calculate the rate of change in flow_out. This uses the simple
differential
// equation Tp*flow_out_dot+flow_outy=Kp*CO(n). Note flow_out is
negative.
flow_out_dot(n) = -flow_out(n)/Tp + (Kp/Tp)*CO(n);
// calculate the new flow out by adding the rate of change times T
flow_out(n+1) = flow_out(n) + flow_out_dot(n)*T;
// integrate the difference between the flow in and flow out.
PV(n+1) = PV(n) + Kt*(flow_in+flow_out(n))*T;
// added by Mr Lu Hing to test the maximum level deviation
if PV(n+1) > maximumLevel then
maximumLevel = PV(n+1);
end
err(n) = SP(n) - PV(n); // calculate error
up = Kc*err(n); // calculate the proportional control output
percent
ui = ui + (Kc*T/Ti)*err(n); // calculate the integrator control
output percent
if ui > (100-up) then // limit the integrator contribution to the
control output
ui = 100-up;
elseif ui < 0-up then
ui = 0-up;
end
CO(n+1) = ui + up; // the control output is the sum of the
integrator and proportional terms
end
PV($)=[]; // LIMIT TO 1200 ITEMS
CO($)=[];
// PLOT THE SIMULATION
// CREATE TO PLOTS USING THE SUBPLOTS FUNCTION
// THE TOP PLOT SHOWS THE SP AND PV. THE BOTTOM PLOT SHOWS THE CO
t=T:T:N*T; // COMPUTE TIME INDEXES. START A TIME T IN INCREMENTS OF T
TO N*T
clf(); // CLEAR OR RESET THE CURRENT GRAPHICS FIGURE
subplot(2,1,1); // PLOT TEMPERATURES ON THE TOP PLOT
plot(t,[SP PV]);
xtitle('Tank Level Control Simulation','Time In Minutes','Tank
Level');
legend("SP","PV");
subplot(2,1,2); // PLOT CONTROL OUTPUT ON THE BOTTOM PLOT
// PLOT THE CONTROL OUTPUT TERMS
plot(t,[CO]);
xtitle('Tank Level Control Simulation','Time In Minutes','Control
Output%');
legend("CO")
maximumLevel // added by Mr Lu Hing to display tha maximum deviation

That isn't very much.
In really difficult cases, when the

Why not? Be specific. You can see that my program changes the inflow.

You removed the derivative term. That invalidates the test.
I am already shit scared to write this posting, but I

If you read the original thread you will see that is the model of a real
system provided to us by an engineer trying to model his system. I
don't understand why you would complain about the model. It was good
for the engineer on www.plcs.net.
My program changes the in_flow variable 3 times to simulate
disturbances. I should probably add another graph that shows the in
flow levels just to make that clear.
Provide us with another one if you don't like that provided. From what
I see both Pieter and Lu Hing have both miss represent the tuning I use
because they have modified the program.
Mr. Lu Hing, what about the derivative time constant or derivative gain?
Your 'small change' got rid of the derivative time constant. Well?
All the gains must 'work together' to achieve the desired response. You
effectively sabotaged my controller and made it look bad. What is wrong
with you guys? You seem to pick and choose the gains you want to use
and ignore the ones you don't with out any concern as to how the gains
work together. See the other thread on iterative tuning.
Here is a link to where I going to keep news group data.
ftp://ftp.deltacompsys.com/public/NG
There are two .gif files. One showing Pieter's tuning and the other
showing my tuning with the Tc set to 0.1 minutes. Which would you
rather use. Both have an max error of about 0.030 meter. My
tanklevel.sce is in the same directory. It has only been modified to
add Pieter's tuning and a max_error variable was added. If you run my
program you will see my tuning provides a slightly smaller peak but the
average error and wear and tear on the pump is much less.
Which one would you use?
Peter Nachtwey

Thank you very much Mr Peter Nachtwey.
a) The reference you gave in the thread definitely had no derivative
action, Maybe you got confused and thought you gave another reference?
Do me a favour and go check the reference again please.
b) You imply I take out the derivative term. I did no such thing. I
took your program and made the changes that I very clearly commented
as my changes.
Yes, thank you very much, but we never doubted that if you include
derivative it can make the control response better. But then you must
consider the response of derivative on the noise, and then you can
come up with even better algorithm like to use feed-forward on the in-
flow (similar to three term boiler drum level control. But those are
other discussions.
This discussion is very clear on comparing P-only to PI- control, The
question was not to find the best control scheme. Do you mind not
changing the subject until we have reached some closure on PI- against
P-only for the specific application as described.
Thank you very much
Lu Hing

OOPS! MY APOLOGIES TO ALL and to Mr Lu Hing. I must have updated my
program since that thread and forgotten that I had done that. We
were talking apples and oranges. All of you were correctly looking
at what I had referenced and I was looking at the updated version. I
should have posted a link to the program I was talking about on my FTP
site.
I APOLOGIZE , I can see how all of you came up with the conclusions
you did and I wasted valuable time.
Please see this site
ftp://ftp.deltacompsys.com/public/NG
The .gif and the updated tanklevel.sce is there. It has the
disturbances and the better PID control.
Peter Nachtwey

No problem Peter, apologies accepted. We all make mistakes sometimes.
I do want to go back on this thread to pick up the main unresolved
point, but first some other points though:
a) First John started it about modelling his tank level control, and
this issue has been sorted out, I think.
b) There was a lot of other messages and ideas, but before going back
to John's difficult level control that has been side-tracked
significantly by Peter's small mistake, maybe first a comment on Fred
Thomasson's two cents. I quote from his posting:

I support this tuning method for level control on tanks that are used
to steady out the flow; this is typical used on surge vessels and are
very applicable in oil refineries where I have done a lot of work. The
objective is to keep the outflow as steady as possible, without
violating the level limits. So you ensure the proportional control
action will "catch" the maximum allowable error, caused by an inflow
disturbance, using the smallest amount of control effort. And then you
calculate the integral action for critical damped response to bring
the level back to setpoint again. So your tuning method starts from,
not a given time response, but a maximum allowable level variation
(ALV).
This concept (albeit in a slight different format), was first
explained to me by a Shell process control engineer, Fatolla Azodi,
more than 15 years ago, so I think it's safe to say that this method
is reasonably well established in industry and it works well.
c) Then there is John's difficult tank level where we were somewhat
side-tracked. Let me quote him again:

...
I have worked on a number of similar "difficult" level control
applications too.
Although Peter's model coefficients that he used (in the very nice
Scilab level control models, thanks Peter) is very typical of many
tank levels in industry, it does not capture the essence of this
specific problem of John's. In a most tank level control, like
Peter's, you can use relatively very strong control action without
stability problems. Peter's example of his best tuning is a case in
point. It's a good desk top exercise to demonstrate the concept, but
you would not really implement strong control action like this on a
chemical plant.
But let's return to John's difficult level control application: In all
the "difficult" level controls, similar to John's, that I have come
across, the relative magnitudes of the tank capacity and apparent dead
time of the actuator response is such that the control system becomes
unstable and force you to use weaker control settings, with the result
that level deviation on an inflow disturbance is sometimes too large
to prevent level trips.
Let me side-track a bit: now this type of application would be
suitable for Peter's derivative control; there's nothing like
derivative control to allow stronger proportional control action
without the loop going unstable.
But .. I would be very careful in using derivative for level control.
The little waves on the liquid surface that Peter referred to in one
if his postings get amplified by the derivative action, so it's not
always a good idea. I say "not always", if you can not "catch" the
level from tripping, you might want to consider derivative action.
Some DCSs (I know ABB's has), PID algorithm let you filter the
derivative only, making it less risky using derivative of course.
So let's stay with PI only for now (but keeping derivative for plan B
of course). For John's application, it would be valid to say that to
use proportional control only (well, you would have a tiny bit of
integral of course, but for all practical purposes you can say it is
proportional only), is the best fit for this purpose.
Now the question is of course: how do you find the proportional gain.
Well, there is more than one way to skin a cat. There are people, like
Peter, who seem to have a very strong dislike of iterative tuning, so
you can model your process and use desk-top tools, nothing wrong with
that at all.
Or you can simply use on-line iterative tuning.
If P-only does not work, then try derivative, you would still use very
little Integral, so it would almost become a PD-controller, or feed-
forward on inflow.
It's up to you and your tank level now my friend, good luck.
Please keep us updated on your progress on this one.
Regards
Pieter Steenekamp

I have a NG ( news group ) directory on my FTP site where I will put
files so we are all talking about the same thing. That way this will
not happen gain.

Yes, over damped is good too if you don't want over shoot. I was
mainly objecting to P only control with gains at -9200.

I will check that out. I don't normally deal with models like K/s so I
don't have a lot of pre made examples I can modify. That is why I
haven't responded. It takes time.

In this simple model the Kp is the product of the Kt and Kp in the
Scilab model. Why can't you calculate this?

I will check this out.

If you have the model you can calculate the error. In the original
problem on www.plcs.net the mellow tuning was enough.

It is hard to know exactly why this happens but I suspect that it is
improper tuning coupled with a poor implementation of the integrator.
In my tanklevel.sce the worst case occurs if the last in_flow is set to
0. In this case the integrator must wind down and during this time the
level keeps going down.

The stronger integrator gain means that it should unwind faster too.
If you were using a Rockwell PLC I was tell you to get a trend.. These
are very informative. Plot the SP PV and CO.

Doesn't the pump goo off while the level is low?

So can you graph this event?

I hope not. If you notice the pump will stop pretty quickly when the
in_flow drops.

I don't think original control with Tc = .25 is very strong. If the Tc
is changed to 3*Tp then the derivative gain isn't required.

If you are using a control valve to control the out flow then that is a
WHOLE different problem. The valve probably is non-linear and the flow
through it isn't linear as it changes as a function of the pressure
drop. I don't see where there would be a dead time in a simpler
application like tanklevel.sce example.

I was wondering when someone would call me on that. There are cures for
that ranging from a simple low pass filter on up. Since PLCs can do
anymore than the low pass filter technique I think I will limit the
tricks to that, for now.
I say "not always", if you can not "catch" the

SIGreg's application on plcs.net requires a derivative gain most of the
time because it has two poles. One for the tank integrator and one for
the pump time constant. Each system must be evaluated on a case by case
basis. A simple Kp/s plant shouldn't require an derivative gain.

Yes, it is a standard feature.

I don't know and am reluctant to say because we really don't know the
kind of information about John's plant. SIGreg on the plcs.net forum
supplied us with the required information.
I think John is using a poorly implemented integrator which makes the
situation worse.
If John's system works like Fred's model ( K/s ) you are probably right
P gain will do the trick. The problem with using P gain only is shown
by your example. The output term from the proportional gain gets too
high. The integrator filters things out a bit. One could do better by
just having an in-flow meter using feed forward with just a P gain.

Look at the interative tuning thread. I used the Ackermann equations to
compute the gains. Look at Pandiani's .pdf on www.plcs.net. He
computes the gains although I think he made a mistake in calculating the
derivative gain. I need to check that.

The problem with iterative tuning is that people change the gains
without knowing what is happening to the poles. Look at Fred's
response. I need to verify what he said but it looks like he has a good
approach and is very mindful of where the poles are.

Tuning shouldn't be a hit or miss process.
Peter Nachtwey

Polytechforum.com is a website by engineers for engineers. It is not affiliated with any of manufacturers or vendors discussed here.
All logos and trade names are the property of their respective owners.