I have installled hydrostatic level sensor 4/20ma on a old yacht fuel tanks.
Everything is working well but as soon as the main engines are running because vibration and tanks just under, the values are moving and start to be unreadable .
Is there any filter available on codesys library (can’t find) or a way to reduice this?
I use REAL values for a HMI .
I tryed FILTER in Oscat library but for some reasons I don’t understand it is not working well.
Because I filter the Iw Inlet, I used FILTER_W but it is worth then nothing.
I tried FILTER_I and with 5 or 8 sec it is not so bad but sometime the value freeze.
Any idea to fixe it?
Thank you for your help.
Rgds
Here is some function I used for filtering purpose.
It take out of the rolling average the min and max values.
FUNCTION_BLOCK fbFilter
VAR_INPUT
rInput : REAL;
END_VAR
VAR_OUTPUT
rOutput : REAL;
END_VAR
VAR CONSTANT
MAX_BUFFER : UINT := 15; (* the bigger the buffer is, the slower the signal will update and be sensitive to noise *)
END_VAR
VAR
iIndex : INT;
iMaxIndex : INT;
arValues : ARRAY [0..MAX_BUFFER] OF REAL;
iLoopIndex : INT;
rMin : REAL;
rMax : REAL;
rSum : REAL;
END_VAR
arValues[iIndex] := rInput;
iMaxIndex := MAX(iIndex, iMaxIndex);
IF (iIndex >= MAX_BUFFER) THEN
iIndex := 0;
ELSE
iIndex := iIndex + 1;
END_IF;
IF (iMaxIndex > 1) THEN
rMin := 3.402823466E+38;
rMax := -3.402823E+38;
rSum := 0;
FOR iLoopIndex := 0 TO iMaxIndex BY 1 DO
IF (arValues[iLoopIndex] < rMin) THEN rMin := arValues[iLoopIndex]; END_IF;
IF (arValues[iLoopIndex] > rMax) THEN rMax := arValues[iLoopIndex]; END_IF;
rSum := rSum + arValues[iLoopIndex];
END_FOR;
rSum := rSum - rMin;
rSum := rSum - rMax;
rOutput := rSum / (iMaxIndex - 1);
ELSE
rSum := 0;
FOR iLoopIndex := 0 TO iMaxIndex BY 1 DO
rSum := rSum + arValues[iLoopIndex];
END_FOR;
rOutput := rSum / (iMaxIndex + 1);
END_IF;
Thank you very much for your answer.
I would like to filter since iw inlet (WORD) because I’m using function blocks after (scale, linear alarms etc…) with this Iword input.
Do you think it is possible?
Do I only have to change rMin and rMax with 0 and 65535? (and of course data type from REAL to WORD)
Thank you for your help
Best regards
LJ
Indeed, if you change the variables for WORD, the system need to be modified:
FUNCTION_BLOCK fbFilter
VAR_INPUT
wInput : WORD;
END_VAR
VAR_OUTPUT
wOutput : WORD;
END_VAR
VAR CONSTANT
MAX_BUFFER : UINT := 15; (* the bigger the buffer is, the slower the signal will update and be sensitive to noise *)
END_VAR
VAR
iIndex : INT;
iMaxIndex : INT;
adwValues : ARRAY [0..MAX_BUFFER] OF DWORD;
iLoopIndex : INT;
dwMin : DWORD;
dwMax : DWORD;
dwSum : DWORD;
END_VAR
adwValues[iIndex] := WORD_TO_DWORD(wInput);
iMaxIndex := MAX(iIndex, iMaxIndex);
IF (iIndex >= MAX_BUFFER) THEN
iIndex := 0;
ELSE
iIndex := iIndex + 1;
END_IF;
IF (iMaxIndex > 1) THEN
dwMin := 4294967295;
dwMax := 0;
dwSum := 0;
FOR iLoopIndex := 0 TO iMaxIndex BY 1 DO
IF (adwValues[iLoopIndex] < dwMin) THEN dwMin := adwValues[iLoopIndex]; END_IF;
IF (adwValues[iLoopIndex] > dwMax) THEN dwMax := adwValues[iLoopIndex]; END_IF;
dwSum := dwSum + adwValues[iLoopIndex];
END_FOR;
dwSum := dwSum - dwMin;
dwSum := dwSum - dwMax;
wOutput := DWORD_TO_WORD(dwSum / (iMaxIndex - 1));
ELSE
dwSum := 0;
FOR iLoopIndex := 0 TO iMaxIndex BY 1 DO
dwSum := dwSum + adwValues[iLoopIndex];
END_FOR;
wOutput := DWORD_TO_WORD(dwSum / (iMaxIndex + 1));
END_IF;
You have to change the internal system for DWORD since you can add up to 15 time the WORD maximum range.