Implementing this pid code that I have, mainly what info I need to pass into the function. There are six variables to pass but I don't really know what to enter.
A bit of background, I am automating my home brewery, and although it is all up and running, the temperature control of the RIMs is all over the place. For those not familiar with what a RIMs is, it is a way of ensuring the grains that are being soaked are kept at a very constant temperature. It does this by using a pump and a heating element to heat fluid taken from the bottom of the soaking vessel and passing it past the heating element and heating the fluid as it goes if needed. The code I have running at the moment is dumb so I need to replace it with something more intelligent, like a PID!
To heat the heater element Plan on using a simple function called every second that will change the amount of time the element is powered from 100ms to 1000ms depending on how much correction to the temperature is needed.
Ok, so I have the code, its just how to use it! I want to get it up and running in a stand alone windows form project using vb.net. I know I need to play with the PID values so it suits my application, but what to enter to get me started?
Many thanks for any help!
Public Function PID_output(ByVal process As Double, ByVal setpoint As Double, ByVal Gain As Double, _
ByVal Integ As Double, ByVal deriv As Double, ByVal deltaT As Double)
Dim Er As Double
Dim Derivative As Double
Dim Proportional As Double
Static Olderror As Double
Static Cont As Double
Static Integral As Double
Static Limiter_Switch As Double
Limiter_Switch = 1
Er = setpoint - process
If ((Cont >= 1 And Er > 0) Or (Cont <= 0 And Er < 0) Or (Integ >= 9999)) Then
Limiter_Switch = 0
Else
Limiter_Switch = 1
End If
Integral = Integral + Gain / Integ * Er * deltaT * Limiter_Switch
Derivative = Gain * deriv * (Er - Olderror) / deltaT
Proportional = Gain * Er
Cont = Proportional + Integral + Derivative
Olderror = Er
If (Cont > 1) Then
Cont = 1
End If
If (Cont < 0) Then
Cont = 0
End If
Return (Cont)
End Function
Using PID for heating process is a bit trickier than typical PID applications. The reason is; when you need to heat probably you start energizing a heater. The power of that heater is the key to how much energy you can pump into the system so that how fast you can heat it up. However, when it comes to cooling, cooling is normally achieved by the nature of the environment.
What I'm trying to say is: the system is not symmetrical.
May I offer you to use different control set according to the "direction" of your control. If the process is cooler than your setpoint, then use controller 1. But, if system is hotter that your setpoint, use controller 2.
For system 1, I definitely advise to use D term because D term is a kind of limiter of how fast your controller is building up the heat on progress. The worry is; many heat control systems have a considerable thermal inertia and lag (delay) of reading back the feedback. This often results in high overshoot (progress is reaching and passing the setpoint with considerable amounts). If exaggerated, will forever oscillate (fluctuate) :)
Also, for cooling effect, say environment is 20deg. Now, if your setpoint is 100 this is something, if your setpoint if 1000 this is totally different. because the Delta T will be different (80 and 980 degrees respectively) and the system response of "trying to get cool" will be a function of Delta T.
Cooling progress is not linear but exponential (like a capacitor discharging over a constant resistor). If your setpoint shall not be changing every day, then you are fine. But if otherwise, you'd better divide your setpoint space into regions and use different controller parameters for different setpoints too.
Where to start:
There are different PID tuning thumb of rules. Look at Ziegler Nichols method. But basically, get your progress cool (initial conditions) then give it full throttle heating power and record the time-heat graph. This graph is called step response and will be estimating the thermal inertial and the system lag for you. This will tell you the typical starting PID values when you check Ziegler Nichols method.
Related
I'm creating a computer game in which there is a computer-controlled car that needs to travel along a straight line (thus making this problem effectively 1-dimensional) and reach a destination coming to a rest at 0 velocity. This car "thinks" every second and decides whether (and by how much) to accelerate or decelerate.
To summarize, I want the car to accelerate as strongly as possible and then stop as rapidly as possible.
Here are the variables that the car must respect:
- RemainingDistance = Our current remaining distance to the destination in meters.
- Velocity = Our current velocity towards the destination in meters/second.
- MaxVelocity = The maximum speed the car can reach.
- Acceleration = The change in velocity per second. The car can change its acceleration every second to any number in the range [0, Acceleration].
- Deceleration = The change in velocity per second. The car can change its deceleration every second to any number in the range [0, Deceleration].
So to be as clear as I can, here's the math that runs every second to update the car simulation:
Acceleration = some amount between [Deceleration, Acceleration] as chosen by the computer
Velocity = Velocity + Acceleration
RemainingDistance = RemainingDistance - Velocity
So my question is: Every time the car "thinks", what formula(s) should it use to determine the ideal value of Acceleration in order to reach its destination (with a 0 final velocity) in as little time as possible?
(In the event that the car's initial velocity is too high and it can't decelerate fast enough to achieve 0 velocity by the time it reaches its destination, then it should come to a rest as close as possible to the destination.)
Please let me know if you have any questions.
I am working a simple game where users create structures in a sector, which is a 10x10 grid. Some structures generate resources and some consume resources. The sector itself might contain some resources outside of any structure. The generators and consumers are related. For example, a well might be generating water, then an splitter be consuming water and making hydrogen and oxygen, while a refinery is consuming hydrogen and oxygen and making rocket fuel, etc.
The rate at which they generate or consume resources can vary by structure - I call this the tick rate. Each time a consumer ticks, it will first attempt to extract those resources from the structures that surround it in the sector. If there are not enough, it will try to get them from the sector's storage. If it is still not enough, the structure will stop. Structures hold the resources that they generate up to some maximum. Once they are full, they will not generate more until some are consumed. If a structure is stopped, it will also not generate more resources, but the resources it already has can still be used by another adjacent structure.
It is not uncommon that there are patterns. For example, if the well is very slow, the splitter will turn off when the well runs out of water, and then the refinery will turn off when the splitter runs out of gases. Then when the well generates again, everything will turn back on.
When the user is playing a sector, I tick the sector continuously at the resolution of shortest tick rate of the sector's structures. This works fine. The pseudo-code looks like this:
const numTicks = (Date.now() - lastTickTime) / shortestTickTime;
let currentTickTime = lastTickTime;
for (i = 0; i < numTicks; i++) {
currentTickTime += shortestTickTime;
// check the consumers - all structures that are consumers
for (curConsumer of consumers) {
if (curConsumer.isRunning &&
(currentTickTime - curConsumer.lastTickTime >= curConsumer.tickRate) {
... check surrounding structures for resources
if (curConsumer.stillNeedsResources) {
... check sector for researches
}
if (curConsumer.stillNeedsResources) {
... no resources available
curConsumer.isRunning = false;
}
}
// check the generators - all structures that are generators
for (curGenerator of generators) {
if (curGenerator.isRunning &&
(currentTickTime - curGenerator.lastTickTime >= curGenerator.tickRate) {
... add the generated resources
}
}
}
}
Now I am dealing with the case of a user coming back to a sector after a long absence - say, a few days - when hundreds or thousands of ticks have passed. If I just naively try to play all of the ticks, it can take several seconds or several minutes to complete.
I am wondering if there are any tips or tricks for simulations of this kind for computing the net change without playing each tick. Or, alternately, if there are changes I can make to the simulation to make this easier to compute. Thanks!
Step 1: Convert the raw data into "graph of nodes" form, where each node represents a machine, and producers are at the bottom and consumers are at the top. For example it might look like:
|
(fuel)
|
Refinery
/ \
/ \
(hydrogen) (oxygen)
\ /
\ /
Splitter
|
(water)
|
well
Note: If a machine has an output buffer (or input buffer/s); then those buffers should be separate nodes. For example, if everything has output buffers it might look like this:
|
(fuel)
|
Refinery output buffer
|
(fuel)
|
Refinery
/ \
/ \
(hydrogen) (oxygen)
| |
Hydrogen Oxygen
output output
buffer buffer
| |
(hydrogen) (oxygen)
\ /
\ /
Splitter
|
(water)
|
Well output buffer
|
(water)
|
well
Step 2: Determine "current steady state average rates" by (initially) working from bottom up (producers to consumers). For example, if a well produces 1 unit of water every 4 ticks then assume it does produce an average of 0.25 water per tick; and if a splitter can convert 1 unit of water into 2 units of hydrogen and 1 unit of oxygen every 3 ticks then that's a max. rate of 0.333 water converted to 0.666 hydrogen and 0.333 oxygen, but you already know the well isn't producing water fast enough and can determine that the splitter will actually consume 0.25 water to produce 0.5 hydrogen and 0.25 oxygen.
Note that if a producer overproduces you will need to backtrack. For example, if a well produces 1 unit of water every 2 ticks then you'd assume it does produce an average of 0.5 water per tick; and if a splitter can convert 1 unit of water into 2 units of hydrogen and 1 unit of oxygen every 3 ticks then you know the well is producing more water than the splitter can consume and have to go back to the well and clamp its output to 0.333 water per tick.
Step 3: Determine when (how many ticks) until the next thing happens that will change the "current steady state average rates". If a resource can become depleted (e.g. the well runs dry) you need to know when that will happen. In the same way, if a "storage vessel" (an output buffer, input buffer, water tank, fuel storage chest, ...) becomes full or empty then you need to know when that will happen too. This is all based on the "current steady state average rates" you have - e.g. if a well's output buffer is empty and gains water (from well) at a rate of 0.5 water per tick and loses water (to splitter) at a rate of 0.33 water per tick; then you can calculate that the quantity it is storing increases at a rate of "0.5 - 0.33 = 0.17 per tick" and (combined with the buffer's capacity) calculate when the output buffer will become full.
Note that "how many ticks until the next thing happens" must also be limited to when you want to stop simulating.
Step 4: Advance time up until the next thing that happens. This mostly means updating the amount of stuff stored in "storage vessels" using the "current steady state average rates" you have; and then modifying any information (e.g. setting a well to "not functioning, ran dry").
Step 5: Repeat the previous steps until you reach the time you want. This is just "if(current_time < stop_time) goto step 2".
Step 6: Update the world with the final state of everything. This is mostly the reverse of step 1 - setting quantities in "storage vessels", marking resources as depleted, etc.
Notes:
You might need to add "transport" as a type of node. For example, if you have conveyor belts taking water from the well to the splitter then that can be simulated like a "storage vessel" but with lag time (e.g. if belt was empty and items start being put on the belt, then it's going to take "length * speed" time before items arrive at the other end).
If you want; you could add "breakdown" to the game (e.g. maybe there's a small chance that a splitter malfunctions and needs to be repaired). This is just an extra thing to take into account at step 3.
Don't forget that you can modify the game design to make it easier. For a start, I would avoid feedback loops (e.g. if the fuel from the reactor is fed into a generator to create power that is consumed by a splitter that ...) because this makes everything significantly harder. I'd also be tempted to avoid "variable speed" things (e.g. miners travelling between an ore field and a drop off point, where the distance the miners travel increases as closer parts of the ore field are consumed so the "average ore per tick" is increasing and never constant).
Don't forget that it's a game - it doesn't have to be 100% perfectly accurate, and only needs to be convincing enough to fool the player. If it's "slightly wrong" (e.g. an output buffer should have 23 items but only has 21 itmes) it's likely that nobody will ever notice.
Depending on other details; you might (or might not) consider stopping early and switching to "simulate one tick at a time". For example, if you need to simulate 12345600 ticks, then you could use the approach I've described for the first 12345500 ticks, then use the approach you already have to do the last 100 ticks. This can help to make some things (e.g. position of items on a conveyor belt) seem a lot more realistic.
I am given the following question:
Now assume the system has no page faults, we are considering adding a TLB that will take
1 nano-second to lookup an address translation. What hit rate (to the nearest 5%) in the TLB is required
to reduce the effective access time to memory by a factor of 2.5?
I am told an average memory access takes 100ns. Since there are 4 memory accesses for a 3 level PT (3 for the page table 1 for physical memory) I deduced that it takes 400ns.
I am then asked to reduce that by a factor of 2.5. So (2/5) *400 = 160ns.
my goal EAT is 160ns. I started setting up the problem and I can't figure out where to go from here.
I am given the following solution but I am just unable to follow it:
Access time = 100 X + (1-x) 400 – 100 ns for hit (read memory), 400ns for
miss
160 = 100 x + 400 – 400x -> x = .8 -> 80% TLB hit rate
Can someone explain to me how they got to this step? I thought EAT was p(time it takes for a hit) + 1-p(time it takes for a miss) where p is the hit rate. isn't the time it takes for a hit 300ns? and then time it takes for a miss is 400ns?
from my logic I tried: p(300) + ((1-p) (400)) but when I went to compute it, I did not get the correct setup as the solution. Can someone explain where my logic is going wrong? Am I wrong about how many memory accesses a hit takes?
backstory
I put together a simple multi-threaded brute-force hash hacking program for a job application test requirement.
Here are some of the particulars
It functions properly, but the performance is quite a bit different between my initial version and this altered portion.
factors
The reason for the alteration was due to increased number of possible combinations between the sample data processing and the test/challenge data processing.
The application test sample was 16^7 total combinations.. which is of course less that uint32 (or 16^8).
the challenge is a 9 length hashed string that produces a hashed long value (that I was given); thus it is 16^9. The size difference was something I accounted for, which is why I took the easy route of putting the initial program together targeting the 7 length Hashed string - getting it to function properly on a smaller scale.
overall
The issue isn't just the increased combinations, it is dramatically slower due to the loop operating using long/int64 or uint64..
when I crunched the numbers using int32 (not even uint32) data types.. I could hear my comp kick it up a notch.. The entire check was done in under 4 minutes. that's 16777216 (16^6) combination checks per thread..
noteworthy - multithreading
I broke everything into worker threads.. 16 of them, 1 for each of the beginning characters.. thus I'm only looking for 16^8 combination on each thread now... which is 1 freaking unit higher than uint32 value (includes 0)...
I'll give a final thought after I put up this code segment..
The function is as followed:
Function Propogate() As Boolean
Propogate = False
Dim combination As System.Text.StringBuilder = New System.Text.StringBuilder(Me.ScopedLetters)
For I As Integer = 1 To (Me.ResultLength - Me.ScopedLetters.Length) Step 1
combination.Append(Me.CombinationLetters.Chars(0))
Next
'Benchmarking feedback - This simply adds values to a list to be checked against to denote progress
Dim ProgressPoint As New List(Of Long)
'###############################
'#[THIS IS THE POINT OF INTEREST]
'# Me.CombinationLetters = 16 #
'# Me.ResultLength = 7 Or 9 # The 7 was the sample size provided.. 9 was the challenge/test
'# Me.ScopedLetters.Length = 1 # In my current implementation
'###############################
Dim TotalCombinations As Long = CType(Me.CombinationLetters.Length ^ (Me.ResultLength - Me.ScopedLetters.Length), Long)
ProgressPoint.Add(1)
ProgressPoint.Add(CType(TotalCombinations / 5, Long))
ProgressPoint.Add(CType(TotalCombinations * 2 / 5, Long))
ProgressPoint.Add(CType(TotalCombinations * 3 / 5, Long))
ProgressPoint.Add(CType(TotalCombinations * 4 / 5, Long))
ProgressPoint.Add(CType(TotalCombinations, Long))
For I As Long = 1 To TotalCombinations Step 1
Me.AddKeyHash(combination.ToString) 'The hashing arithmetic and Hash value check is done at this call.
Utility.UpdatePosition(Me.CombinationLetters, combination) 'does all the incremental character swapping and string manipulation..
If ProgressPoint.Contains(I) Then
RaiseEvent OnProgress(CType((I / TotalCombinations) * 100, UInteger).ToString & " - " & Me.Name)
End If
Next
Propogate = True
End Function
I already have an idea of what I could try, drop it down the int32 again and put another loop around this loop (16 iterations)
But there might be better alternative, so I would like to hear from the community on this one.
Would a For Loop using double point precision cycle better?
by the way, how coupled is long types and arithmetic to cpu architecture.. specifically cacheing?
My development comp is old.. Pentium D running XP Professional x64 .. my excuse is that if it runs in my environment, it will likely run on Win Server 2003..
In the end, this could have likely been a hardware issue.. my old workstation did not survive much longer after doing this project.
I am currently busy on writing a small ball physics engine for my programming course in Win32 API and c++. I have finished the GDI backbuffer renderer and the whole GUI (couple of more things to adjust) but i am very near to completion. The only big obstacles that last are ball to ball collision (but i can fix this on my own) but the biggest problem of them all is the bouncing of the balls. What happens is that i throw a ball and it really falls, but once it bounces it will bounce higher than the point were i released it??? the funny thing is, it only happens if below a certain height. This part is the physics code:
(If you need any more code or explanation, please ask, but i would greatly appreciate it if you guys could have a look at my code.)
#void RunPhysics(OPTIONS &o, vector<BALL*> &b)
{
UINT simspeed = o.iSimSpeed;
DOUBLE DT; //Delta T
BOOL bounce; //for playing sound
DT= 1/o.REFRESH;
for(UINT i=0; i<b.size(); i++)
{
for(UINT k=0; k<simspeed; k++)
{
bounce=false;
//handle the X bounce
if( b.at(i)->rBall.left <= 0 && b.at(i)->dVelocityX < 0 ) //ball bounces against the left wall
{
b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof;
bounce=true;
}
else if( b.at(i)->rBall.right >= SCREEN_WIDTH && b.at(i)->dVelocityX > 0) //ball bounces against the right wall
{
b.at(i)->dVelocityX = b.at(i)->dVelocityX * -1 * b.at(i)->dBounceCof;
bounce=true;
}
//handle the Y bounce
if( b.at(i)->rBall.bottom >= SCREEN_HEIGHT && b.at(i)->dVelocityY > 0 ) //ball bounces against the left wall
{
//damping of the ball
if(b.at(i)->dVelocityY < 2+o.dGravity/o.REFRESH)
{
b.at(i)->dVelocityY = 0;
}
//decrease the Velocity of the ball according to the bouncecof
b.at(i)->dVelocityY = b.at(i)->dVelocityY * -1*b.at(i)->dBounceCof;
b.at(i)->dVelocityX = b.at(i)->dVelocityX * b.at(i)->dBounceCof;
bounce=true;
}
//gravity
b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH;
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
//METER IS DEFINED GLOBALLY AS 100 which is the amount of pixels in a meter
b.at(i)->pOrigin.x += b.at(i)->dVelocityX/o.REFRESH*METER;
b.at(i)->UpdateRect();
}
}
return;
}
You are using the Euler method of integration. It is possible that your time step (DT) is too large. Also there seems to be a mistake on the row that updates the Y coordinate:
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
You have already added the gravity to the velocity, so you don't need to add it to the position and you are not multiplying the velocity by DT. It should be like this:
b.at(i)->pOrigin.y += b.at(i)->dVelocityY * DT;
Furthermore there appears to be some confusion regarding the units (the way METER is used).
Okay, a few things here.
You have differing code paths for bounce against left wall and against right wall, but the code is the same. Combine those code paths, since the code is the same.
As to your basic problem: I suspect that your problem stems from the fact that you apply the gravity after you apply any damping forces / bounce forces.
When do you call RunPhysics? In a timer loop? This code is just an approximation and no exact calculation. In the short interval of delta t, the ball has already changed his position and velocity a litte bit which isn't considered in your algorithm and produces little mistakes. You'll have to compute the time until the ball hits the ground and predict the changes.
And the gravity is already included in the velocity, so don't add it twice here:
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
By the way: Save b.at(i) in a temporary variable, so you don't have to recompute it in every line.
Ball* CurrentBall = b.at(i);
ANSWER!!ANSWER!!ANSWER!! but i forgot my other account so i can't flag it :-(
Thanks for all the great replies, it really helped me alot! The answers that you gave were indeed correct, a couple of my formulas were wrong and some code optimisation could be done, but none was really a solution to the problem. So i just sat down with a piece of paper and started calculation every value i got from my program by hand, took me like two hours :O But i did find the solution to my problem:
The problem is that as i update my velocity (whith corrected code) i get a decimal value, no problem at all. Later i increase the position in Y by adding the velocity times the Delta T, which is a verry small value. The result is a verry small value that needs to be added. The problem is now that if you draw a Elipse() in Win32 the point is a LONG and so all the decimal values are lost. That means that only after a verry long period, when the values velocity starts to come out of the decimal values something happens, and that alongside with that, the higher you drop the ball the better the results (one of my symptons) The solution to this problem was really simple, ad an extra DOUBLE value to my Ball class which contained the true position (including decimals) of my ball. During the RenderFrame() you just take the floor or ceiling value of the double to draw the elipse but for all the calculations you use the Double value. Once again thanks alot for all your replies, STACKOVERFLOW PEOPLE ROCK!!!
If your dBounceCof is > 1 then, yes your ball will bounce higher.
We do not have all the values to be able to reply to your question.
I don't think your equation for position is right:
b.at(i)->dVelocityY += (o.dGravity)/o.REFRESH;
This is v=v0+gt - that seems fine, although I'd write dGravity*DT instead of dGravity/REFRESH_FREQ.
b.at(i)->pOrigin.y += b.at(i)->dVelocityY + (1/2)*o.dGravity/o.REFRESH*DT*METER;
But this seems off: It is eqivalent to p = p0+v + 1/2gt^2.
You ought to multiply velocity * time to get the units right
You are scaling the gravity term by pixels/meter, but not the velocity term. So that ought to be multiplied by METER also
You have already accounted for the effect of gravity when you updated velocity, so you don't need to add the gravity term again.
Thanks for the quick replies!!! Sorry, i should have been more clear, the RunPhysics is beiing run after a PeekMessage. I have also added a frame limiter which makes sure that no more calculations are done per second than the refresh rate of the monitor. My dleta t is therefore 1 second devided by the refresh rate. Maybe my DT is actually too small to calculate, although it's a double value??? My cof of restitution is adjustable but starts at 0.9
You need to recompute your position on bounce, to make sure you bounce from the correct place on the wall.
I.e. resolve the exact point in time when the bounce occured, and calculate new velocity/position based on that direction change (partially into a "frame" of calculation) to make sure your ball does not move "beyond" the walls, more and more on each bounce.
W.r.t. time step, you might want to check out my answer here.
In a rigid body simulation, you need to run the integration up to the instant of collision, then adjust the velocities to avoid penetration at the collision, and then resume the integration. It's sort of an instantaneous kludge to cover the fact that rigid bodies are an approximation. (A real ball deforms during a collision. That's hard to model, and it's unnecessary for most purposes.)
You're combining these two steps (integrating the forces and resolving the collisions). For a simple simulation like you've shown, it's probably enough to skip the gravity bit on any iteration where you've handled a vertical bounce.
In a more advanced simulation, you'd split any interval (dt) that contains a collision at the actual instance of collision. Integrate up to the collision, then resolve the collision (by adjusting the velocity), and then integrate for the rest of the interval. But this looks like overkill for your situation.