How to keep the output signal of a PID block unchanged after a fixed time point? - pid

I build a fluid model with a PID control system, and I wanna run my model until reaching a steady state and then keep the output signal of the PID system unchanged, so I could do step excitation stability tests. But right now I am not sure how to keep the output signal of the PID control system unchanged after a fixed time point. So I have to use a logical switch to change the signal source at a fixed time point.
My question is:
How could keep the output signal of a Block Component unchanged after a fixed time point?

I dont't think there is a suitable block in the Modelica Standard Library.
But would that code do it?
model KeepValueTime
extends Modelica.Blocks.Interfaces.SISO;
parameter Modelica.Units.SI.Time t = Modelica.Constants.inf "Time at which the value shall be kept";
Real u_keep(start=0) "Value to be output when 'keepValue = true'";
equation
if time < t then
y = u;
else
y = u_keep;
end if;
when time >= t then
u_keep = u;
end when;
annotation (uses(Modelica(version="4.0.0")));
end KeepValueTime;
A bit more general with a Boolean input:
model KeepValue
extends Modelica.Blocks.Interfaces.SISO;
Real u_keep(start=0) "Value to be output when 'keepValue = true'";
Modelica.Blocks.Interfaces.BooleanInput keepValue annotation (Placement(transformation(
extent={{-20,-20},{20,20}},
rotation=0,
origin={-120,80}), iconTransformation(extent={{-140,60},{-100,100}}, rotation=0)));
equation
if not keepValue then
y = u;
else
y = u_keep;
end if;
when keepValue then
u_keep = u;
end when;
annotation (uses(Modelica(version="4.0.0")));
end KeepValue;
A quick test:
...seems to do what you need:

An alternative to the solution suggested by Markus A. could be to switch the control error to zero. This will freeze the controller output, provided that the switch is done when the system is already in steady state (zero control error).

Related

Understanding code sbuf_remove(sbuf_t *sp) from book CSAPP? : issue for location of P(&sp->items)

As reading the book < Computer Systems: A Programmer's Perspective > and in the chapter of Concurrent Programming, I saw a this function:
int sbuf_remove(sbuf_t *sp){
int item; '
P(&sp->items);
P(&sp->mutex);
if (++sp->front >= sp->n)
sp-> front = 0;
item = sp->buf[sp->front]
V(&sp->mutex);
V(&sp->slots);
return item;
}
After reading the code, I think some problematic situation.
Problematic Situation's conditions :
&sp->items = 1 ,
two consumers reach at P(&sp->items) code at same time (before none of them reach to P(&sp->mutex);
In this situation, I think two consumers should have race and make problem.
(After one consumer_1 finish sbuf_remove, items become 0 but consumer_2 already pass P(&sp->items) code. Therefore consumer_2 fail to get correct item and return unexpectable value.)
I am wondering why package developer did not use mutex's lock code before enter items, slots semasphore.
I mean the code should be changed like this. Isn't it more safe than original code?
P(&sp->mutex);
P(&sp->items);
if (++sp->front >= sp->n)
sp-> front = 0;
item = sp->buf[sp->front]
V(&sp->slots);
V(&sp->mutex);
Remember that sem_wait waits until the semaphore is nonzero before atomically decrementing it. So if two consumers reach P(&sp->items) at the same time with sp->items==1, one of them will decrement items and go on to remove the last item. The other will see that items == 0 and block until some producer adds an item. They cannot both pass P(&sp->items). I don't see any race here.
On the other hand your "more safe" suggestion is a little too safe. Suppose a consumer enters sbuf_remove when the queue is empty, so sp->items == 0. It takes the mutex and then blocks (still holding the mutex!) waiting for sp->items to become positive, which will only happen when a producer adds an item. But in order to add an item to the queue, the producer presumably would need to take the mutex, which it can't do because the consumer holds it. We thus have a classic deadlock.

Monitor flashing when running a Windows SendInput API

Well, I certainly should go to python since I did several functions of this type, keyboard event and mouse event, but decide to try to learn the windows api.
My goal is to know when button 1 of the mouse is pressed.
I created this file in a very beginner way, it returns in mouseData only 0.
The curious thing is that whenever I run it, it flashes my monitor at short intervals in blinks, but between 1 second with it off. Very strange that, execution is not viable.
Could someone help me understand and try to execute to see if it is only here.
Code:
int main()
{
DWORD mouseData = 0;
MOUSEINPUT tagMouse;
tagMouse.dx = 0;
tagMouse.dy = 0;
tagMouse.mouseData = mouseData;
tagMouse.dwFlags = MOUSEEVENTF_XDOWN;
tagMouse.dwExtraInfo = 0;
INPUT tagInput;
tagInput.type = INPUT_MOUSE;
tagInput.mi = tagMouse;
while (true) {
if (GetAsyncKeyState(VK_DELETE)) break;
SendInput(1, &tagInput, sizeof(INPUT));
printf("KEYWORD: %d\n", mouseData);
Sleep(500);
}
system("pause");
return 0;
}
I can reproduce your reported 'symptoms' - and the effect is really brutal!
Now, while I cannot offer a full explanation, I can offer a fix! You have an uninitialized field in your tagMouse structure (the time member, which is a time-stamp used by the system). Setting this to zero (which tells the system to generate its own time-stamp) fixes the problem. So, just add this line to your other initializer statements:
//...
tagMouse.dwExtraInfo = 0;
tagMouse.time = 0; // Adding this line fixes it!
//...
Note: I, too, would appreciate a fuller explanation; however, an uninitialized field, to me, smells like undefined behaviour! I have tried a variety of other values (i.e. not zero) for the time field but haven't yet found one that works.
The discussion here on devblogs may help. This quote seems relevant:
And who knows what sort of havoc that will create if a program checks
the timestamps and notices that they are either from the future or
have traveled back in time.

Matlab: For loop with window array

This is my one dimensional array A, containing 10 numbers:
A = [-8.92100000000000 10.6100000000000 1.33300000000000 ...
-2.57400000000000 -4.52700000000000 9.63300000000000 ...
4.26200000000000 16.9580000000000 8.16900000000000 4.75100000000000];
I want the loop to go through like this; (calculating mean interval wise) - Interval length of 2,4,8
(a(1)+a(2))/2 - value stored in one block of a matrix say m= zeros(10)
then (a(1)+a(2)+a(3)+a(4))/4 ------ mean-----
then (a(1)+a(2)..... a(8))/8
Then shift indexes:
(a(2)+a(3))/2; - mean
(a(2)+a(3)+a(4)+a(5))/4
(a(2)+a(3)...a(9))/8
SO basically 2^n length interval
%____ my code _____%
A= newArrayy;
sum=0;
storeD = zeros(3,9);
flag=true;
for k=1:9
n=1;
while(true)
if(k+(2^n-1)<10)
meanSum= mean(A(k):A(k+2^n-1))
storeD(n,k)= meanSum;
n=n+1;
else
flag=false;
end
end
end
I need to find standard deviation, covariance and mean for each interval, but I get an error on the meanSum line.
In the meanSum line, you should write
A(k:k+2^n-1)
You want to access the elements ranging from k to k+2^n-1. Therefore you have to provide the range to the selection operation.
A few suggestions:
Use a search engine or a knowlegde base to gather information on the error message you received.
Try to understand which operation failed, and how it should work in principle (in your case: the colon operator, e.g. http://de.mathworks.com/help/matlab/ref/colon.html)
If your own efforts don't lead to success, at least post the error message you get to make the question more clear. Better yet, provide a minimal working example. In your case one or two lines of code would suffice.
A = [-8.92100000000000 10.6100000000000 1.33300000000000 ...
-2.57400000000000 -4.52700000000000 9.63300000000000 ...
4.26200000000000 16.9580000000000 8.16900000000000 4.75100000000000];
sum=0;
storeD = zeros(3,9);
for k=1:9
n=1;
while(1==1)
if(k+(2^n-1)<=10)
meanSum= mean(A(k:k+2^n-1));
storedD(n,k)= meanSum
covVar= cov(A(k:k+2^n-1));
storedC(n,k)= covVar
stdDev= std(A(k:k+2^n-1));
storedS(n,k)= stdDev
n=n+1;
else
break;
end
end
end
So this worked :D Thanks for the help! There was an error in while loop as i didn't use a break to exit the loop.

Low Pass filter in C

I'm implementing a low pass filter in C wih the PortAudio library.
I record my microphone input with a script from PortAudio itself. There I added the following code:
float cutoff = 4000.0;
float filter(float cutofFreq){
float RC = 1.0/(cutofFreq * 2 * M_PI);
float dt = 1.0/SAMPLE_RATE;
float alpha = dt/(RC+dt);
return alpha;
}
float filteredArray[numSamples];
filteredArray[0] = data.recordedSamples[0];
for(i=1; i<numSamples; i++){
if(i%SAMPLE_RATE == 0){
cutoff = cutoff - 400;
}
data.recordedSamples[i] = data.recordedSamples[i-1] + (filter(cutoff)*(data.recordedSamples[i] - data.recordedSamples[i-1]));
}
When I run this script for 5 seconds it works. But when I try to run this for more then 5 seconds it fails. The application records everything, but crashes on playback. If I remove the filter, the application works.
Any advice?
The problem:
you are lowering the cutoff frequency by 400 Hz everytime i%SAMPLE_RATE == 0
never stop so you go below zero
this is not done once per second !!!
instead every time your for passes through second barrier in your data
that can occur more often then you think if you are not calling your calls in the right place
which is not seen in your code
you are filtering in wrong oorder
... a[i]=f(a[i],a[i-1]; i++;
that means you are filtering with already filtered a[i-1] value
What to do with it
check the code placement
it should be in some event like on packed done sompling
or in thread after some Sleep(...); (or inside timer)
change the cut off changing (handle edge cases)
reverse filter for direction
Something like this:
int i_done=0;
void on_some_timer()
{
cutoff-=400;
if (cutoff<1) cutoff=1; // here change 1 for limit frequency
if (numSamples!=i_done)
for (i=numSamples-1,i>=i_done;i--)
data.recordedSamples[i] = data.recordedSamples[i-1] + (filter(cutoff)*(data.recordedSamples[i] - data.recordedSamples[i-1]));
i_done=numSamples;
}
if your code is already OK (you did not post th whole thing so I can missing something)
then just add the if (cutoff<1) cutoff=1; after cutoff change

Returning program to pre-triggered state

First this gets triggered:
if ((temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit) | (temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit))
activateAlarm(channelID);
Activate alarm is triggered, then from there:
void activateAlarm(int channelID);
{ while (temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit || temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit)
{
logSubsystem(temperatureChannel[channelID].currentTemperature);
}
}
Then alarm screen is triggered with following case:
int logSubsystem(int currentTemperature)
case 'F': //if user input is 'F'
case 'f': //if user input is 'f'
currentTemperature--;
printf("your current exceeded temp is %i\n \n", currentTemperature);
if (currentTemperature <= 100 || currentTemperature >= 50);
compareLimit();
break; //exits loop
How do I set up this function so that if the user decrements with F and gets the current temperature to below the limit (<100, or >50), then it will return back to the compareLimit function and the requirement for the high limit/low limit triggered state will be FALSE, returning the program to its original pre-alarm state?
I think you would benefit considerably from thinking a lot about how your program flows. Right now, what I can deduce of your program flow is:
You have an outer loop that checks the temperature, on at least one channel ID. Inside that loop, you have the if statement you first showed us.
Then activate alarm does some other stuff, but loops until the temperature goes down, calling logSubsystem.
logSubsystem then presumably gets some kind of user input, and from there, you want it to call to your initial function, presumably called prepare limit.
The problem with this is that none of these functions ever complete. They all call each other, and you'll eventually get a stack overflow. Nice, since that's the name of this site, but not something you want to aspire to.
What you basically need is a state machine. You need something that keeps track of values, looks at those values, and calls functions that return that operate on those values. There should only be one loop, and it should do all the control of what happens based on what those values are. The good news is, you have all of this in place already. temperatureChannel is keeping track of the values for you, and you have while loops a-plenty.
Let me give you my suggestion of the way I suggest your program should flow:
bool checkTemperatureValuesOutOfRange(int channelID) {
// this is just a convenience, to make the state machine flow easier.
return (temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit) || // note the || not just one |
(temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit);
}
void actOnUserInput() {
char input = // ... something that gets a user input. It should check if any is available, otherwise return.
switch (input) {
case 'F':
case 'f':
temperatureChannel[channelID].currentTemperature--;
break; // This doesn't exit the loop - it gets you out of the switch statement
}
void activateAlarm(int channelID) {
// presumably this does something other than call logSubsystem?
// if that's all it does, just call it directly
// note - no loop here
logSubsystem(channelID);
}
void logSubsystem(int channelID) { // Not the current temperature - that's a local value, and you want to set the observed value
// I really think actOnUserInput should be (an early) part of the while loop below.
// It's just another input for the state machine, but I'll leave it here per your design
// Presumably actually logs things, too, otherwise it's an unnecessary function
actOnUserInput();
}
while (TRUE) { // this is the main loop of your function, and shouldn't exit unless the program does
// do anything else you need to - check other stuff
// maybe have a for loop going through different channelIDs?
if (checkTemperatureValuesOutOfRange(channelID)) {
activateAlarm(channelId);
// do anything else you need to
}
I'm sure you can see lots of differences between your code and mine. Here are some key things to consider:
All the functions now return. The master while loop calls functions that check status, and calls function that change status.
I would highly suggest acting on the user input as part of the master while loop. It's just another input to the state machine. Get it, act on it, and then check your statuses. You presumably need to have some input from the user, otherwise you'll never get in a bad state in the first place.
Right now, activate alarm happens every time. With the code you showed, that's fine - because logSubsystem was all that was being called. If you only want the alarm to ring once, keep a boolean tracker inside temperatureChannel[channelId] that says if the alarm rang, set it true within activateAlarm, and then reset it to false based on the return value of checkTemperatureValuesOutOfRange.
Rather than leaving yourself in the activateAlarm/logSubsystem area, you return each time, and check your values each time to see if you're still there. This is the key point - your functions should be fast, and not monopolize your processor. Make each function do just one sort of thing, and have all the control come from within the master loop.
I made a lot of changes to your code, and I don't know if you're allowed to make all of them, but you'll need something similar to this. It's much more robust, and gives you room to grow all around.

Resources