Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
proview
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Esteban Blanc
proview
Commits
95e99d16
Commit
95e99d16
authored
May 14, 2014
by
Claes Sjofors
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Plc control, new algorithm for PID and CompPID, and windup limit in Inc3P-object (refs #177)
parent
16ed5c5d
Changes
8
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
822 additions
and
418 deletions
+822
-418
bcomp/lib/rt/src/rt_plc_bcomp.c
bcomp/lib/rt/src/rt_plc_bcomp.c
+85
-61
bcomp/wbl/bcomp/src/basecomponent.wb_load
bcomp/wbl/bcomp/src/basecomponent.wb_load
+228
-146
src/lib/rt/src/rt_plc_pid.c
src/lib/rt/src/rt_plc_pid.c
+99
-70
src/wbl/pwrb/src/pwrb_c_inc3p.wb_load
src/wbl/pwrb/src/pwrb_c_inc3p.wb_load
+15
-1
src/wbl/pwrb/src/pwrb_c_mode.wb_load
src/wbl/pwrb/src/pwrb_c_mode.wb_load
+19
-21
src/wbl/pwrb/src/pwrb_c_pid.wb_load
src/wbl/pwrb/src/pwrb_c_pid.wb_load
+189
-88
src/wbl/pwrb/src/pwrb_sv_se.txt
src/wbl/pwrb/src/pwrb_sv_se.txt
+90
-31
src/wbl/pwrb/src/pwrb_td_windupmaskenum.wb_load
src/wbl/pwrb/src/pwrb_td_windupmaskenum.wb_load
+97
-0
No files found.
bcomp/lib/rt/src/rt_plc_bcomp.c
View file @
95e99d16
...
@@ -240,6 +240,11 @@ void CompPID_Fo_init( pwr_sClass_CompPID_Fo *o)
...
@@ -240,6 +240,11 @@ void CompPID_Fo_init( pwr_sClass_CompPID_Fo *o)
#define DALG 8
/* Derivative part exists */
#define DALG 8
/* Derivative part exists */
#define DAVV 16
/* Derivative part working on control difference */
#define DAVV 16
/* Derivative part working on control difference */
#define IWUP 1
/* Windup limitation on I part */
#define BIWUP 2
/* Windup limitation on Bias and I part */
#define BPIWUP 4
/* Windup limitation on Bias PI part */
#define BPIDWUP 8
/* Windup limitation on Bias and PID part (Default, old funcionality */
void
CompPID_Fo_exec
(
plc_sThread
*
tp
,
void
CompPID_Fo_exec
(
plc_sThread
*
tp
,
pwr_sClass_CompPID_Fo
*
o
)
pwr_sClass_CompPID_Fo
*
o
)
{
{
...
@@ -252,6 +257,9 @@ void CompPID_Fo_exec( plc_sThread *tp,
...
@@ -252,6 +257,9 @@ void CompPID_Fo_exec( plc_sThread *tp,
float
ut
;
float
ut
;
float
dut
;
float
dut
;
float
kd
;
float
kd
;
float
absut
;
float
gain
;
pwr_sClass_CompPID
*
co
=
(
pwr_sClass_CompPID
*
)
o
->
PlcConnectP
;
pwr_sClass_CompPID
*
co
=
(
pwr_sClass_CompPID
*
)
o
->
PlcConnectP
;
if
(
!
co
)
if
(
!
co
)
...
@@ -284,104 +292,120 @@ void CompPID_Fo_exec( plc_sThread *tp,
...
@@ -284,104 +292,120 @@ void CompPID_Fo_exec( plc_sThread *tp,
ddiff
=
((
co
->
PidAlg
&
DAVV
)
!=
0
)
?
ddiff
=
((
co
->
PidAlg
&
DAVV
)
!=
0
)
?
(
co
->
ControlDiff
-
eold
)
/
*
o
->
ScanTime
:
(
co
->
ControlDiff
-
eold
)
/
*
o
->
ScanTime
:
(
co
->
ProcVal
-
xold
)
/
*
o
->
ScanTime
;
(
co
->
ProcVal
-
xold
)
/
*
o
->
ScanTime
;
if
((
co
->
DerGain
<=
0
.
0
)
||
(
co
->
DerTime
<=
0
))
if
((
(
co
->
DerGain
*
*
o
->
ScanTime
)
>=
co
->
DerTime
)
||
(
co
->
DerTime
<=
0
))
co
->
FiltDer
=
ddiff
;
/* No Filter */
co
->
FiltDer
=
ddiff
;
/* No Filter */
else
{
else
{
kd
=
1
.
0
/
(
1
.
0
+
co
->
DerGain
*
*
o
->
ScanTime
/
co
->
DerTime
);
kd
=
1
.
0
/
(
1
.
0
+
co
->
DerGain
*
*
o
->
ScanTime
/
co
->
DerTime
);
co
->
FiltDer
+=
(
ddiff
-
derold
)
*
(
1
.
0
-
kd
);
co
->
FiltDer
+=
(
ddiff
-
derold
)
*
(
1
.
0
-
kd
);
}
}
if
(
co
->
Inverse
==
0
)
gain
=
co
->
Gain
;
else
gain
=
-
co
->
Gain
;
if
(
co
->
Force
)
{
if
(
co
->
Force
)
{
/* Force */
/* Force */
dut
=
co
->
OutVal
;
co
->
OutChange
=
co
->
ForcVal
-
co
->
OutVal
;
co
->
OutVal
=
co
->
ForcVal
;
co
->
OutVal
=
co
->
OutWindup
=
co
->
ForcVal
;
co
->
OutChange
=
co
->
OutVal
-
dut
;
co
->
EndMin
=
FALSE
;
co
->
EndMin
=
FALSE
;
co
->
EndMax
=
FALSE
;
co
->
EndMax
=
FALSE
;
/* Adjust for bumpless transfer to auto */
co
->
PDManOffset
=
co
->
OutVal
-
gain
*
co
->
ControlDiff
-
co
->
BiasGain
*
co
->
Bias
;
if
((
co
->
PidAlg
&
IALG
)
!=
0
)
co
->
AbsOut
=
0
.
0
;
else
co
->
AbsOut
=
co
->
OutVal
;
if
(
co
->
WindupMask
<
BIWUP
)
co
->
OutWindup
-=
co
->
BiasGain
*
co
->
Bias
;
if
(
co
->
WindupMask
<
BPIWUP
)
co
->
OutWindup
-=
gain
*
co
->
ControlDiff
;
co
->
AbsOut
=
co
->
OutVal
-
co
->
OutWindup
;
}
}
else
{
else
{
/* Auto mode */
/* Auto mode */
if
((
co
->
PidAlg
&
IALG
)
!=
0
)
{
/* Incremental algorithm */
dut
=
absut
=
0
.
0
;
if
((
co
->
PidAlg
&
IALG
)
!=
0
)
/* Incremental algorithm */
{
/* Integral-part */
/* Integral-part */
if
((
*
o
->
IntOffP
==
FALSE
)
&&
(
co
->
IntTime
>
0
))
if
((
*
o
->
IntOffP
==
FALSE
)
&&
(
co
->
IntTime
>
0
))
dut
=
co
->
ControlDiff
*
*
o
->
ScanTime
/
co
->
IntTime
;
dut
=
co
->
ControlDiff
*
*
o
->
ScanTime
/
co
->
IntTime
;
if
((
co
->
PidAlg
&
PALG
)
!=
0
)
dut
*=
gain
;
else
gain
=
0
.
0
;
/* Pure I-controller */
/* Bias */
if
(
co
->
WindupMask
>=
BIWUP
)
/* Windup on Bias */
dut
+=
co
->
BiasGain
*
(
co
->
Bias
-
bfold
);
else
absut
=
co
->
BiasGain
*
co
->
Bias
;
/* P-part */
if
(
co
->
WindupMask
>=
BPIWUP
)
/* Windup on P */
dut
+=
((
co
->
PidAlg
&
PAVV
)
!=
0
)
?
gain
*
(
co
->
ControlDiff
-
eold
)
:
gain
*
(
co
->
ProcVal
-
xold
)
;
else
else
dut
=
0
;
absut
+=
gain
*
co
->
ControlDiff
;
if
((
co
->
PidAlg
&
PALG
)
!=
0
)
{
/* Not pure I-controller */
/* Derivative-part */
/* Derivative-part */
if
((
co
->
PidAlg
&
DALG
)
!=
0
)
{
if
((
co
->
PidAlg
&
DALG
)
!=
0
)
if
(
co
->
WindupMask
>=
BPIDWUP
)
/* Windup on D */
dut
+=
(
co
->
FiltDer
-
derold
)
*
co
->
DerTime
;
dut
+=
gain
*
(
co
->
FiltDer
-
derold
)
*
co
->
DerTime
;
/* P-part */
else
dut
+=
((
co
->
PidAlg
&
PAVV
)
!=
0
)
?
absut
+=
gain
*
co
->
FiltDer
*
co
->
DerTime
;
co
->
ControlDiff
-
eold
:
co
->
ProcVal
-
xold
;
dut
*=
co
->
Gain
;
}
}
if
(
co
->
Inverse
!=
0
)
dut
=
-
dut
;
/* Bias */
dut
+=
co
->
BiasGain
*
(
co
->
Bias
-
bfold
);
/* Limit output */
/* Limit output */
ut
=
co
->
OutVal
+
dut
;
co
->
OutWindup
+=
dut
;
if
(
co
->
MaxOut
>
co
->
MinOut
)
{
if
(
ut
>
co
->
MaxOut
)
{
if
(
co
->
OutWindup
>
co
->
MaxWindup
)
{
ut
=
co
->
MaxOut
;
co
->
OutWindup
=
co
->
MaxWindup
;
co
->
EndMin
=
FALSE
;
co
->
EndMax
=
TRUE
;
co
->
EndMax
=
TRUE
;
}
else
if
(
co
->
OutWindup
<
co
->
MinWindup
)
{
}
co
->
OutWindup
=
co
->
MinWindup
;
else
if
(
ut
<
co
->
MinOut
)
{
co
->
EndMin
=
TRUE
;
ut
=
co
->
MinOut
;
co
->
EndMin
=
TRUE
;
co
->
EndMax
=
FALSE
;
}
else
{
if
(
co
->
EndMin
&&
(
ut
>=
(
co
->
MinOut
+
co
->
EndHys
)))
co
->
EndMin
=
FALSE
;
if
(
co
->
EndMax
&&
(
ut
<=
(
co
->
MaxOut
-
co
->
EndHys
)))
co
->
EndMax
=
FALSE
;
}
}
}
ut
=
co
->
OutWindup
+
absut
;
if
(
ut
>
co
->
MaxOut
)
ut
=
co
->
MaxOut
;
else
if
(
ut
<
co
->
MinOut
)
ut
=
co
->
MinOut
;
dut
+=
absut
-
co
->
AbsOut
;
}
}
else
{
else
/* Nonincremental algorithm */
/* Nonincremental algorithm */
{
/* P-part */
/* P-part */
ut
=
co
->
ControlDiff
;
ut
=
co
->
ControlDiff
;
/* Derivative-part */
/* Derivative-part */
if
((
co
->
PidAlg
&
DALG
)
!=
0
)
if
((
co
->
PidAlg
&
DALG
)
!=
0
)
ut
+=
co
->
FiltDer
*
co
->
DerTime
;
ut
+=
co
->
FiltDer
*
co
->
DerTime
;
/* Gain */
/* Gain */
ut
*=
co
->
Gain
;
ut
*=
gain
;
if
(
co
->
Inverse
!=
0
)
ut
=
-
ut
;
/* Bias */
/* Bias and Man offset*/
ut
+=
co
->
BiasGain
*
co
->
Bias
;
if
(
co
->
PDAbsFlag
)
co
->
PDManOffset
=
0
;
ut
+=
co
->
BiasGain
*
co
->
Bias
+
co
->
PDManOffset
;
/* Limit output */
/* Limit output */
if
(
co
->
MaxOut
>
co
->
MinOut
)
{
if
(
co
->
MaxOut
>
co
->
MinOut
)
if
(
ut
>
co
->
MaxOut
)
{
{
ut
=
co
->
MaxOut
;
if
(
ut
>
co
->
MaxOut
)
ut
=
co
->
MaxOut
;
co
->
EndMin
=
FALSE
;
else
if
(
ut
<
co
->
MinOut
)
ut
=
co
->
MinOut
;
co
->
EndMax
=
TRUE
;
}
else
if
(
ut
<
co
->
MinOut
)
{
ut
=
co
->
MinOut
;
co
->
EndMin
=
TRUE
;
co
->
EndMax
=
FALSE
;
}
else
{
if
(
co
->
EndMin
&&
(
ut
>=
(
co
->
MinOut
+
co
->
EndHys
)))
co
->
EndMin
=
FALSE
;
if
(
co
->
EndMax
&&
(
ut
<=
(
co
->
MaxOut
-
co
->
EndHys
)))
co
->
EndMax
=
FALSE
;
}
}
}
dut
=
ut
-
co
->
OutVal
;
dut
=
ut
-
co
->
OutVal
;
absut
=
ut
;
}
}
/* Output Auto */
/* Output Auto */
co
->
OutChange
=
dut
;
co
->
OutChange
=
dut
;
co
->
OutVal
=
ut
;
co
->
OutVal
=
ut
;
co
->
AbsOut
=
absut
;
}
}
/* Transfer outputs */
/* Transfer outputs */
...
...
bcomp/wbl/bcomp/src/basecomponent.wb_load
View file @
95e99d16
This diff is collapsed.
Click to expand it.
src/lib/rt/src/rt_plc_pid.c
View file @
95e99d16
...
@@ -44,7 +44,6 @@
...
@@ -44,7 +44,6 @@
#include "pwr_baseclasses.h"
#include "pwr_baseclasses.h"
#include "rt_plc.h"
#include "rt_plc.h"
#include "rt_plc_timer.h"
#include "rt_plc_timer.h"
#include "rt_plc_pid.h"
/* PLC RUTINER */
/* PLC RUTINER */
...
@@ -53,9 +52,13 @@
...
@@ -53,9 +52,13 @@
function: accumulate output change from controller
function: accumulate output change from controller
and convert to Open or Close orders.
and convert to Open or Close orders.
2014-02-18 Werner Limit acc to new attribute "MaxWindup"
@aref inc3p Inc3p
@aref inc3p Inc3p
*/
*/
void
inc3p_init
(
pwr_sClass_inc3p
*
object
)
void
inc3p_init
(
pwr_sClass_inc3p
*
object
)
{
{
object
->
Acc
=
0
;
object
->
Acc
=
0
;
}
}
...
@@ -157,6 +160,13 @@ void inc3p_exec(
...
@@ -157,6 +160,13 @@ void inc3p_exec(
}
}
}
}
}
}
/* Limit output 2014-02-18 / Werner */
if
((
object
->
Acc
>
object
->
MaxWindup
)
&&
(
object
->
MaxWindup
>
0
.
0
))
object
->
Acc
=
object
->
MaxWindup
;
if
((
object
->
Acc
<
-
object
->
MaxWindup
)
&&
(
object
->
MaxWindup
>
0
.
0
))
object
->
Acc
=
-
object
->
MaxWindup
;
}
}
/*_*
/*_*
...
@@ -355,15 +365,19 @@ void mode_exec(
...
@@ -355,15 +365,19 @@ void mode_exec(
Possible to turn off integration and to force
Possible to turn off integration and to force
output to desired value.
output to desired value.
Revision: 2011-01-18 / Werner
New Attributes 2014-02-18 / Werner:
Error in filtered derivate part corrected.
WindupMask Config
MinWindup Config
MaxWindup Config
PDManOffset Internal
OutWindup Internal
@aref pid Pid
@aref pid Pid
*/
*/
void
pid_exec
(
void
pid_exec
(
plc_sThread
*
tp
,
plc_sThread
*
tp
,
pwr_sClass_pid
*
object
)
pwr_sClass_pid
*
object
)
{
{
/* Define Algoritm bitmask */
/* Define Algoritm bitmask */
...
@@ -373,6 +387,11 @@ void pid_exec(
...
@@ -373,6 +387,11 @@ void pid_exec(
#define DALG 8
/* Derivative part exists */
#define DALG 8
/* Derivative part exists */
#define DAVV 16
/* Derivative part working on control difference */
#define DAVV 16
/* Derivative part working on control difference */
#define IWUP 1
/* Windup limitation on I part */
#define BIWUP 2
/* Windup limitation on Bias and I part */
#define BPIWUP 4
/* Windup limitation on Bias PI part */
#define BPIDWUP 8
/* Windup limitation on Bias and PID part (Default, old funcionality */
float
xold
;
/* Local variables */
float
xold
;
/* Local variables */
float
eold
;
float
eold
;
float
bfold
;
float
bfold
;
...
@@ -381,6 +400,8 @@ void pid_exec(
...
@@ -381,6 +400,8 @@ void pid_exec(
float
ut
;
float
ut
;
float
dut
;
float
dut
;
float
kd
;
float
kd
;
float
absut
;
float
gain
;
/* Save old values */
/* Save old values */
xold
=
object
->
ProcVal
;
xold
=
object
->
ProcVal
;
...
@@ -402,73 +423,93 @@ object->ControlDiff = object->ProcVal - object->SetVal;
...
@@ -402,73 +423,93 @@ object->ControlDiff = object->ProcVal - object->SetVal;
ddiff
=
((
object
->
PidAlg
&
DAVV
)
!=
0
)
?
ddiff
=
((
object
->
PidAlg
&
DAVV
)
!=
0
)
?
(
object
->
ControlDiff
-
eold
)
/
*
object
->
ScanTime
:
(
object
->
ControlDiff
-
eold
)
/
*
object
->
ScanTime
:
(
object
->
ProcVal
-
xold
)
/
*
object
->
ScanTime
;
(
object
->
ProcVal
-
xold
)
/
*
object
->
ScanTime
;
if
((
object
->
DerGain
<=
0
.
0
)
||
(
object
->
DerTime
<=
0
))
if
((
(
object
->
DerGain
*
*
object
->
ScanTime
)
>=
object
->
DerTime
)
||
(
object
->
DerTime
<=
0
))
object
->
FiltDer
=
ddiff
;
/* No Filter */
object
->
FiltDer
=
ddiff
;
/* No Filter */
else
{
else
{
kd
=
1
.
0
/
(
1
.
0
+
object
->
DerGain
*
*
object
->
ScanTime
/
object
->
DerTime
);
kd
=
1
.
0
/
(
1
.
0
+
object
->
DerGain
*
*
object
->
ScanTime
/
object
->
DerTime
);
object
->
FiltDer
+=
(
ddiff
-
derold
)
*
(
1
.
0
-
kd
);
object
->
FiltDer
+=
(
ddiff
-
derold
)
*
(
1
.
0
-
kd
);
}
}
if
(
object
->
Inverse
==
0
)
gain
=
object
->
Gain
;
else
gain
=
-
object
->
Gain
;
if
(
object
->
Force
)
if
(
object
->
Force
)
/* Force */
/* Force */
{
{
dut
=
object
->
OutVal
;
object
->
OutChange
=
object
->
ForcVal
-
object
->
OutVal
;
object
->
OutVal
=
object
->
ForcVal
;
object
->
OutVal
=
object
->
OutWindup
=
object
->
ForcVal
;
object
->
OutChange
=
object
->
OutVal
-
dut
;
object
->
EndMin
=
FALSE
;
object
->
EndMin
=
FALSE
;
object
->
EndMax
=
FALSE
;
object
->
EndMax
=
FALSE
;
/* Adjust for bumpless transfer to auto */
object
->
PDManOffset
=
object
->
OutVal
-
gain
*
object
->
ControlDiff
-
object
->
BiasGain
*
object
->
Bias
;
if
((
object
->
PidAlg
&
IALG
)
!=
0
)
object
->
AbsOut
=
0
.
0
;
else
object
->
AbsOut
=
object
->
OutVal
;
if
(
object
->
WindupMask
<
BIWUP
)
object
->
OutWindup
-=
object
->
BiasGain
*
object
->
Bias
;
if
(
object
->
WindupMask
<
BPIWUP
)
object
->
OutWindup
-=
gain
*
object
->
ControlDiff
;
object
->
AbsOut
=
object
->
OutVal
-
object
->
OutWindup
;
}
}
else
else
/* Auto mode */
/* Auto mode */
{
{
dut
=
absut
=
0
.
0
;
if
((
object
->
PidAlg
&
IALG
)
!=
0
)
if
((
object
->
PidAlg
&
IALG
)
!=
0
)
/* Incremental algorithm */
/* Incremental algorithm */
{
{
/* Integral-part */
/* Integral-part */
if
((
*
object
->
IntOffP
==
FALSE
)
&&
(
object
->
IntTime
>
0
))
if
((
*
object
->
IntOffP
==
FALSE
)
&&
(
object
->
IntTime
>
0
))
dut
=
object
->
ControlDiff
*
*
object
->
ScanTime
/
object
->
IntTime
;
dut
=
object
->
ControlDiff
*
*
object
->
ScanTime
/
object
->
IntTime
;
else
dut
=
0
;
if
((
object
->
PidAlg
&
PALG
)
!=
0
)
dut
*=
gain
;
if
((
object
->
PidAlg
&
PALG
)
!=
0
)
else
gain
=
0
.
0
;
/* Pure I-controller */
/* Not pure I-controller */
{
/* Bias */
/* Derivative-part */
if
(
object
->
WindupMask
>=
BIWUP
)
/* Windup on Bias */
if
((
object
->
PidAlg
&
DALG
)
!=
0
)
dut
+=
object
->
BiasGain
*
(
object
->
Bias
-
bfold
);
dut
+=
(
object
->
FiltDer
-
derold
)
*
object
->
DerTime
;
else
absut
=
object
->
BiasGain
*
object
->
Bias
;
/* P-part */
/* P-part */
if
(
object
->
WindupMask
>=
BPIWUP
)
/* Windup on P */
dut
+=
((
object
->
PidAlg
&
PAVV
)
!=
0
)
?
dut
+=
((
object
->
PidAlg
&
PAVV
)
!=
0
)
?
object
->
ControlDiff
-
eold
:
gain
*
(
object
->
ControlDiff
-
eold
)
:
object
->
ProcVal
-
xold
;
gain
*
(
object
->
ProcVal
-
xold
)
;
dut
*=
object
->
Gain
;
else
absut
+=
gain
*
object
->
ControlDiff
;
/* Derivative-part */
if
((
object
->
PidAlg
&
DALG
)
!=
0
)
{
if
(
object
->
WindupMask
>=
BPIDWUP
)
/* Windup on D */
dut
+=
gain
*
(
object
->
FiltDer
-
derold
)
*
object
->
DerTime
;
else
absut
+=
gain
*
object
->
FiltDer
*
object
->
DerTime
;
}
}
if
(
object
->
Inverse
!=
0
)
dut
=
-
dut
;
/* Bias */
dut
+=
object
->
BiasGain
*
(
object
->
Bias
-
bfold
);
/* Limit output */
/* Limit output */
ut
=
object
->
OutVal
+
dut
;
object
->
OutWindup
+=
dut
;
if
(
object
->
MaxOut
>
object
->
MinOut
)
{
if
(
object
->
OutWindup
>
object
->
MaxWindup
)
{
if
(
ut
>
object
->
MaxOut
)
object
->
OutWindup
=
object
->
MaxWindup
;
{
object
->
EndMax
=
TRUE
;
ut
=
object
->
MaxOut
;
}
else
if
(
object
->
OutWindup
<
object
->
MinWindup
)
{
object
->
EndMin
=
FALSE
;
object
->
OutWindup
=
object
->
MinWindup
;
object
->
EndMax
=
TRUE
;
object
->
EndMin
=
TRUE
;
}
else
if
(
ut
<
object
->
MinOut
)
{
ut
=
object
->
MinOut
;
object
->
EndMin
=
TRUE
;
object
->
EndMax
=
FALSE
;
}
else
{
if
(
object
->
EndMin
&&
(
ut
>=
(
object
->
MinOut
+
object
->
EndHys
)))
object
->
EndMin
=
FALSE
;
if
(
object
->
EndMax
&&
(
ut
<=
(
object
->
MaxOut
-
object
->
EndHys
)))
object
->
EndMax
=
FALSE
;
}
}
}
ut
=
object
->
OutWindup
+
absut
;
if
(
ut
>
object
->
MaxOut
)
ut
=
object
->
MaxOut
;
else
if
(
ut
<
object
->
MinOut
)
ut
=
object
->
MinOut
;
dut
+=
absut
-
object
->
AbsOut
;
}
}
else
else
...
@@ -480,39 +521,27 @@ else
...
@@ -480,39 +521,27 @@ else
if
((
object
->
PidAlg
&
DALG
)
!=
0
)
if
((
object
->
PidAlg
&
DALG
)
!=
0
)
ut
+=
object
->
FiltDer
*
object
->
DerTime
;
ut
+=
object
->
FiltDer
*
object
->
DerTime
;
/* Gain */
/* Gain */
ut
*=
object
->
Gain
;
ut
*=
gain
;
if
(
object
->
Inverse
!=
0
)
ut
=
-
ut
;
/* Bias */
/* Bias and Man offset */
ut
+=
object
->
BiasGain
*
object
->
Bias
;
if
(
object
->
PDAbsFlag
)
object
->
PDManOffset
=
0
;
ut
+=
object
->
BiasGain
*
object
->
Bias
+
object
->
PDManOffset
;
/* Limit output */
/* Limit output */
if
(
object
->
MaxOut
>
object
->
MinOut
)
if
(
object
->
MaxOut
>
object
->
MinOut
)
{
{
if
(
ut
>
object
->
MaxOut
)
if
(
ut
>
object
->
MaxOut
)
ut
=
object
->
MaxOut
;
{
else
if
(
ut
<
object
->
MinOut
)
ut
=
object
->
MinOut
;
ut
=
object
->
MaxOut
;
object
->
EndMin
=
FALSE
;
object
->
EndMax
=
TRUE
;
}
else
if
(
ut
<
object
->
MinOut
)
{
ut
=
object
->
MinOut
;
object
->
EndMin
=
TRUE
;
object
->
EndMax
=
FALSE
;
}
else
{
if
(
object
->
EndMin
&&
(
ut
>=
(
object
->
MinOut
+
object
->
EndHys
)))
object
->
EndMin
=
FALSE
;
if
(
object
->
EndMax
&&
(
ut
<=
(
object
->
MaxOut
-
object
->
EndHys
)))
object
->
EndMax
=
FALSE
;
}
}
}
dut
=
ut
-
object
->
OutVal
;
dut
=
ut
-
object
->
OutVal
;
absut
=
ut
;
}
}
/* Output Auto */
/* Output Auto */
object
->
OutChange
=
dut
;
object
->
OutChange
=
dut
;
object
->
OutVal
=
ut
;
object
->
OutVal
=
ut
;
object
->
AbsOut
=
absut
;
}
}
}
}
src/wbl/pwrb/src/pwrb_c_inc3p.wb_load
View file @
95e99d16
...
@@ -52,7 +52,8 @@ SObject pwrb:Class
...
@@ -52,7 +52,8 @@ SObject pwrb:Class
! The input signal OutChange is regarded as a control
! The input signal OutChange is regarded as a control
! error. This error is transformed into a time by
! error. This error is transformed into a time by
! multiplication with Gain. The product is added to
! multiplication with Gain. The product is added to
! accumulator Acc.
! accumulator Acc. The absolute value of Acc is limited
! to MaxWindup.
!
!
! If the absolute value of Acc > MinTim either the output
! If the absolute value of Acc > MinTim either the output
! Open or Close is set. If Acc > MinTim an incremental
! Open or Close is set. If Acc > MinTim an incremental
...
@@ -193,6 +194,18 @@ SObject pwrb:Class
...
@@ -193,6 +194,18 @@ SObject pwrb:Class
Attr GraphName = "MaxTim"
Attr GraphName = "MaxTim"
EndBody
EndBody
EndObject
EndObject
!/**
! Maximum windup in seconds
! The absolute value of Acc will never be greater than MaxWindup
! Typically less or equal than running time from open to closed
! Default 30 seconds. Lessor equal to zero means no limitation.
!*/
Object MaxWindup $Intern 19
Body SysBody
Attr TypeRef = "pwrs:Type-$Float32"
Attr GraphName = "MaxWindup"
EndBody
EndObject
Object OpenP $Intern 8
Object OpenP $Intern 8
Body SysBody
Body SysBody
Attr Flags |= PWR_MASK_POINTER
Attr Flags |= PWR_MASK_POINTER
...
@@ -387,6 +400,7 @@ SObject pwrb:Class
...
@@ -387,6 +400,7 @@ SObject pwrb:Class
Object Template Inc3P
Object Template Inc3P
Body RtBody
Body RtBody
Attr Gain = 1.0
Attr Gain = 1.0
Attr MaxWindup = 30.0
EndBody
EndBody
EndObject
EndObject
EndObject
EndObject
...
...
src/wbl/pwrb/src/pwrb_c_mode.wb_load
View file @
95e99d16
...
@@ -175,8 +175,6 @@ SObject pwrb:Class
...
@@ -175,8 +175,6 @@ SObject pwrb:Class
Object SetVal $Output 7
Object SetVal $Output 7
Body SysBody
Body SysBody
Attr PgmName = "SetVal"
Attr PgmName = "SetVal"
Attr Flags |= PWR_MASK_STATE
Attr Flags |= PWR_MASK_NOEDIT
Attr TypeRef = "pwrs:Type-$Float32"
Attr TypeRef = "pwrs:Type-$Float32"
Attr GraphName = "SV"
Attr GraphName = "SV"
EndBody
EndBody
...
@@ -380,16 +378,26 @@ SObject pwrb:Class
...
@@ -380,16 +378,26 @@ SObject pwrb:Class
! Mode object display. The values may be changed in the
! Mode object display. The values may be changed in the
! more info form of the Mode object.
! more info form of the Mode object.
!*/
!*/
Object SetMinShow $Intern 21
Body SysBody
Attr TypeRef = "pwrs:Type-$Float32"
Attr GraphName = "SetMinShow"
EndBody
EndObject
Object SetMaxShow $Intern 20
Object SetMaxShow $Intern 20
Body SysBody
Body SysBody
Attr TypeRef = "pwrs:Type-$Float32"
Attr TypeRef = "pwrs:Type-$Float32"
Attr GraphName = "SetMaxShow"
Attr GraphName = "SetMaxShow"
EndBody
EndBody
EndObject
EndObject
Object SetMinShow $Intern 21
!/**
! Specifies the engineering unit of XSetVal / SetVal / SetMinShow /
! SetMaxShow, e.g. kg. Used in the Mode object display.
!*/
Object SetEngUnit $Intern 24
Body SysBody
Body SysBody
Attr TypeRef = "pwrs:Type-$
Float32
"
Attr TypeRef = "pwrs:Type-$
String16
"
Attr GraphName = "Set
MinShow
"
Attr GraphName = "Set
EngUnit
"
EndBody
EndBody
EndObject
EndObject
!/**
!/**
...
@@ -398,32 +406,22 @@ SObject pwrb:Class
...
@@ -398,32 +406,22 @@ SObject pwrb:Class
! object in the Mode display. The values may be changed
! object in the Mode display. The values may be changed
! in the more info form of the Mode object.
! in the more info form of the Mode object.
!*/
!*/
Object OutMaxShow $Intern 22
Body SysBody
Attr TypeRef = "pwrs:Type-$Float32"
Attr GraphName = "OutMaxShow"
EndBody
EndObject
Object OutMinShow $Intern 23
Object OutMinShow $Intern 23
Body SysBody
Body SysBody
Attr TypeRef = "pwrs:Type-$Float32"
Attr TypeRef = "pwrs:Type-$Float32"
Attr GraphName = "OutMinShow"
Attr GraphName = "OutMinShow"
EndBody
EndBody
EndObject
EndObject
!/**
Object OutMaxShow $Intern 22
! Specifies the engineering unit of SetMinShow /
! SetMaxShow, e.g. kg. Used in the Mode object display.
! OutEngUnit
!*/
Object SetEngUnit $Intern 24
Body SysBody
Body SysBody
Attr TypeRef = "pwrs:Type-$
String16
"
Attr TypeRef = "pwrs:Type-$
Float32
"
Attr GraphName = "
SetEngUnit
"
Attr GraphName = "
OutMaxShow
"
EndBody
EndBody
EndObject
EndObject
!/**
!/**
! Specifies the engineering unit of OutMinShow /
! Specifies the engineering unit of XForcVal / OutVal /
! OutMaxShow e.g. %. Used in the Mode object display.
! ForcVal / OutMinShow / OutMaxShow e.g. %.
! Used in the Mode object display.
!*/
!*/
Object OutEngUnit $Intern 25
Object OutEngUnit $Intern 25
Body SysBody
Body SysBody
...
...
src/wbl/pwrb/src/pwrb_c_pid.wb_load
View file @
95e99d16
This diff is collapsed.
Click to expand it.
src/wbl/pwrb/src/pwrb_sv_se.txt
View file @
95e99d16
...
@@ -7509,14 +7509,15 @@ satta under en tid som
...
@@ -7509,14 +7509,15 @@ satta under en tid som
@image orm_en1-100.gif
@image orm_en1-100.gif
Insignalen OutChange betraktas som ett reglerfel. Detta fel överförs till en tid
Insignalen OutChange betraktas som ett reglerfel. Detta fel överförs till en tid
genom multiplikation med Gain . Produkten adderas till ackumulatorn Acc .
genom multiplikation med Gain . Produkten adderas till ackumulatorn Acc.
Absolutvärdet av Acc begränsas till MaxWindup.
Om absolut värdet av Acc är större än MinTim sätts någon av utgångarna Open
Om absolut värdet av Acc är större än MinTim sätts någon av utgångarna Open
eller Close till TRUE.
eller Close till TRUE.
Om Acc > MinTim sätts 'öka' signalen (= Open ) så länge som Acc
=
0 , om, å
Om Acc > MinTim sätts 'öka' signalen (= Open ) så länge som Acc
>
0 , om, å
andra sidan, Acc < - MinTim sätts 'minska' signalen (= Close ) så länge som
andra sidan, Acc < - MinTim sätts 'minska' signalen (= Close ) så länge som
Acc
=
0. Vid varje exekvering räknas värdet av Acc ned respektive upp med ett
Acc
<
0. Vid varje exekvering räknas värdet av Acc ned respektive upp med ett
tidsbelopp av ScanTime , beroende på om 'öka' eller 'minska' signalen satts.
tidsbelopp av ScanTime , beroende på om 'öka' eller 'minska' signalen satts.
För att undvika 'obefogade' styringrepp, som skulle kunna skada ställdon vid
För att undvika 'obefogade' styringrepp, som skulle kunna skada ställdon vid
...
@@ -7608,6 +7609,12 @@ Ackumulerad styrsignal - ingrepp i form av tid.
...
@@ -7608,6 +7609,12 @@ Ackumulerad styrsignal - ingrepp i form av tid.
Ackumulerad löptid utan ingrepp.
Ackumulerad löptid utan ingrepp.
</attr>
</attr>
<attr>MaxWindup
Absolutvärdet av Acc begränsas till MaxWindupsekunder, för att undvika oändlig
uppvridning vid felsatta parametrar. Negativt eller noll ger ingen begränsning.
Bör vara nära gångtid från helt stängd till helt öppen. Default 30 sek.
</attr>
<attr>TimerFlag
<attr>TimerFlag
Markerar aktiv timer.
Markerar aktiv timer.
</attr>
</attr>
...
@@ -8922,13 +8929,13 @@ objektets objektbild. Gr
...
@@ -8922,13 +8929,13 @@ objektets objektbild. Gr
</attr>
</attr>
<attr>SetEngUnit
<attr>SetEngUnit
Anger ingenjörsenheten för
SetMinShow / SetMaxShow , t.ex kg. Används i
Anger ingenjörsenheten för
XSetVal / SetVal / SetMinShow / SetMaxShow, t.ex kg.
Mode-objektets objektbild.
Används i
Mode-objektets objektbild.
</attr>
</attr>
<attr>OutEngUnit
<attr>OutEngUnit
Anger ingenjörsenheten för
OutMinShow / OutMaxShow , t.ex %. Används i
Anger ingenjörsenheten för
XForcVal / OutVal /ForcVal / OutMinShow / OutMaxShow, t.ex %.
Mode-objektets objektbild.
Används i
Mode-objektets objektbild.
</attr>
</attr>
<attr>PidObjDid
<attr>PidObjDid
...
@@ -10361,10 +10368,14 @@ bara genom att det st
...
@@ -10361,10 +10368,14 @@ bara genom att det st
Vid P- och PD-algoritm används en absolut algoritm. Utsignalen kan då alltså inte
Vid P- och PD-algoritm används en absolut algoritm. Utsignalen kan då alltså inte
ligga stabilt skilt från noll utan regleravvikelse, annat än om man använder en
ligga stabilt skilt från noll utan regleravvikelse, annat än om man använder en
framkopplingssignal.
framkopplingssignal. Om flaggan PDAbsFlag sitter, så beräknas en offset i manuell mod,
Vid alla algoritmer med I-del baseras hela tiden förändringar i utsignalen på
så att vi får en stötfri övergång till auto.
förändringar i insignalerna. Man kan fortfarande stänga av integrereringen med
Vid alla algoritmer med I-del delas utsignalen upp i två delar ned hjälp av masken WindupMask.
en insignal till objektet.
I-delen ingår alltid i OutWindup, medanBias, P-delen och D-delen kan tillhöra antingen OutWindup
eller AbsOut.
OutWindup begränsas av MinWindup och MaxWindup, vilket sätter flaggorna EndMin och EndMax.
Resten av utsignalen lagras i AbsOut, och total utsignal begränsas med MinOut och MaxOut
Man kan även stänga av integrereringen med en insignal till objektet.
Pid-objektet har två utgångar som båda kan användas som styrsignal. Vilken som
Pid-objektet har två utgångar som båda kan användas som styrsignal. Vilken som
används i det enskilda fallet beror på hur regleringen är ordnad:
används i det enskilda fallet beror på hur regleringen är ordnad:
...
@@ -10388,25 +10399,35 @@ s
...
@@ -10388,25 +10399,35 @@ s
skulle bli utan filtrering.
skulle bli utan filtrering.
En framkopplingssignal, Bias, kan inkluderas i algoritmen genom en ingångssignal
En framkopplingssignal, Bias, kan inkluderas i algoritmen genom en ingångssignal
till objektet.
till objektet. Förstärkning framkoppling anges med BiasGain.
Utvärdet, OutVal, begränsas till intervallet { MinOut, MaxOut }. Det innebär att
Regulatorns utsignal OutVal är uppdelad i två delar, OutWindup och AbsOut.
I-delen innefattas alltid i OutWindup. Med WindupMask kan man styra även Bias,
P-delen och D-delen till OutWindup.
OutWindup, begränsas till intervallet { MinWindup, MaxWindup }. Det innebär att
man kan tappa det stabila läget vid en orolig reglering, speciellt vid inkopplad
man kan tappa det stabila läget vid en orolig reglering, speciellt vid inkopplad
D-del.
D-del. Om man sätter flaggan WindupMask till BIP, så tar man bort D-delens inflytande
på OutWindup. Man kan även sätta den till BI eller I för att ta bort P-delen och
Bias från OutWindup.
Den totala utsignalen OutVal begränsas till intervallet { MinOut , MaxOut }.
Exempel: Vi har en ganska orolig flödesreglering (utsignal 0-100 %) och reglerar
Exempel: Vi har en ganska orolig flödesreglering (utsignal 0-100 %) och reglerar
nära maxvarvet för pumpen.
Vi behöver styra ut i snitt 98 % för att nå önskat
nära maxvarvet för pumpen.
WindupMask = BPID. Vi behöver styra ut i snitt 98 % för
börvärde. Utsignalen fladdrar ca +- 5 % pga störningar. Om MaxOut är 100 %, så
att nå önskat börvärde. Utsignalen fladdrar ca +- 5 % pga störningar.
innebär det att regulatorn bottnar regelbundet. Utsignalen kommer då att svänga
Om MaxWindup är 100 %, så innebär det att regulatorn bottnar regelbundet. Utsignalen
mellan 90 och 100 % med en medelutsignal på ca 95%, och vi når inte önskat
kommer då att svänga
mellan 90 och 100 % med en medelutsignal på ca 95%, och vi når inte önskat
börvärde.
börvärde.
Lösning: Sätt MinOut och MaxOut till -10 % resp 110 %. Utsignalen kommer att
Lösning: Sätt WindupMask till I eller BI. Störningarna kommer inte att påverka MaxWindup.
svänga mellan 93 och 103% med ett medel på 98%, och vi uppnår önskat börvärde.
Utsignalen får sedan begränsas till 0 - 100 % utanför PID-regulatorn.
För en servoventil med positionsreglering, kan man vilja ha en långsam I-del för läckagekontroll,
begränsad till +- 20 %. Sätt WindupMask till I eller BI.
Sätt MinWindup = -20% och MaxWindup till +20%, MinOutput = -100 %, MaxOutput = 100 %
EndMin och EndMax kan användas för läckagelarm.
Regulatorn har stötfri omkoppling AUTO / MANUAL och efter annan tvångsstyrning av
Regulatorn har stötfri omkoppling AUTO / MANUAL och efter annan tvångsstyrning av
regulatorn.
regulatorn.
Dock ej vid P- eller PD-reglering.
Dock ej vid P- eller PD-reglering
, om man har PDAbsFlag satt
.
EXEMPEL 1
EXEMPEL 1
...
@@ -10638,8 +10659,8 @@ operat
...
@@ -10638,8 +10659,8 @@ operat
</attr>
</attr>
<attr>OutChange
<attr>OutChange
Regulatorns syrsignal baserad på 'incremental form'
.
Regulatorns syrsignal baserad på 'incremental form'
, eller förändring i styrsignalen
vid 'positional form'.
Attributet avser styrsignalsförändringen mellan två konsekutiva exekveringar;
Attributet avser styrsignalsförändringen mellan två konsekutiva exekveringar;
dvs. OutVal t - OutVal t-1 .
dvs. OutVal t - OutVal t-1 .
</attr>
</attr>
...
@@ -10649,14 +10670,14 @@ Reglerfelet (= ProcVal - SetVal ).
...
@@ -10649,14 +10670,14 @@ Reglerfelet (= ProcVal - SetVal ).
</attr>
</attr>
<attr>EndMin
<attr>EndMin
Om beräknat värde på Out
Val inte tillhör intervallet { MinOut , MaxOut
} ska
Om beräknat värde på Out
Windup inte tillhör intervallet { MinWindup , MaxWindup
} ska
begränsning ske till motsvarande intervallgräns. Attributet anger om sådan
begränsning ske till motsvarande intervallgräns. Attributet anger om sådan
begränsning skett vid den senaste exekveringen eller ej.
begränsning skett vid den senaste exekveringen eller ej.
Om begränsning görs mot
Om begränsning görs mot
-- Min
Out
, ska EndMin sättas TRUE
-- Min
Windup
, ska EndMin sättas TRUE
-- Max
Out
, ska EndMax sättas TRUE
-- Max
Windup
, ska EndMax sättas TRUE
annars är de FALSE.
annars är de FALSE.
...
@@ -10748,11 +10769,10 @@ V
...
@@ -10748,11 +10769,10 @@ V
<attr>MinOut
<attr>MinOut
I driftläge AUTO och CASCADE ska den utställda styrsignlaen OutVal vara i
I driftläge AUTO och CASCADE ska den utställda styrsignlaen OutVal vara i
intervallet { MinOut , MaxOut }. Flaggorna EndMin / EndMax används för att
intervallet { MinOut , MaxOut }.
signalera då begränsning sker.
Om OutVal är större än MaxOut eller mindre än MinOut , begränsas OutVal
Om OutVal är större än MaxOut eller mindre än MinOut , begränsas OutVal
till värdet av motsvarande intervallgräns.
till värdet av motsvarande intervallgräns.
Om MinOut = MaxOut sker ingen begränsning.
Om MinOut
>
= MaxOut sker ingen begränsning.
</attr>
</attr>
<attr>MaxOut
<attr>MaxOut
...
@@ -10909,6 +10929,45 @@ EndMin / EndMax flaggorna.
...
@@ -10909,6 +10929,45 @@ EndMin / EndMax flaggorna.
Filtrerad derivata sparas till nästa exekevering.
Filtrerad derivata sparas till nästa exekevering.
</attr>
</attr>
<attr>PDAbsFlag
Anger att utsignalen beräknas direkt med regleravvikelsen.
Vid nollvärde beräknas en offset i manuell mod, så att vi får stötfri övergång till auto.
</attr>
<attr>WindupMask
Möjliga värden är:
1 -- I Bara I-delen begränsas i OutWindup
2 -- BI I-delen och Bias begränsas i OutWindup
4 -- BIP Också P-delen begränsas i OutWindup
8 -- BIPD Hela utsignalen, även D-delen begränsas i OutWindup
</attr>
<attr>MinWindup
I driftläge AUTO och CASCADE ska den utställda styrsignalen OutWindup vara i
intervallet { MinWindup , MaxWindup }. Flaggorna EndMin / EndMax används för att
signalera då begränsning sker.
Om OutWindup är större än MaxWindup eller mindre än MinWindup , begränsas OutWindup
till värdet av motsvarande intervallgräns.
Om MinWindup >= MaxWindup sker ingen begränsning.
</attr>
<attr>MaxWindup
Se MinOut
</attr>
<attr>PDManOffset
Offset beräknas i manuell mod, och används vid P och PD-algoritm
för att få stötfri övergång till auto.
</attr>
<attr>OutWindup
Utsignal som begränsas av MinWindup och MaxWindup
</attr>
<attr>AbsOut
Utsignaldel som ligger utanför OutWindup
</attr>
<attr>OpMod
<attr>OpMod
OpMod = MANUAL (=1)
OpMod = MANUAL (=1)
Då Mode-objektets for-utgång blir TRUE tvingas Pid-objekt utgång
Då Mode-objektets for-utgång blir TRUE tvingas Pid-objekt utgång
...
...
src/wbl/pwrb/src/pwrb_td_windupmaskenum.wb_load
0 → 100644
View file @
95e99d16
!
! Proview Open Source Process Control.
! Copyright (C) 2005-2014 SSAB EMEA AB.
!
! This file is part of Proview.
!
! This program is free software; you can redistribute it and/or
! modify it under the terms of the GNU General Public License as
! published by the Free Software Foundation, either version 2 of
! the License, or (at your option) any later version.
!
! This program is distributed in the hope that it will be useful
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with Proview. If not, see <http://www.gnu.org/licenses/>
!
! Linking Proview statically or dynamically with other modules is
! making a combined work based on Proview. Thus, the terms and
! conditions of the GNU General Public License cover the whole
! combination.
!
! In addition, as a special exception, the copyright holders of
! Proview give you permission to, from the build function in the
! Proview Configurator, combine Proview with modules generated by the
! Proview PLC Editor to a PLC program, regardless of the license
! terms of these modules. You may copy and distribute the resulting
! combined work under the terms of your choice, provided that every
! copy of the combined work is accompanied by a complete copy of
! the source code of Proview (the version used to produce the
! combined work), being distributed under the terms of the GNU
! General Public License plus this exception.
!
! pwrb_windupmaskenum.wb_load -- Defines the mask type WindupMaskEnum
!
SObject pwrb:Type
!/**
! @Version 1.0
! @Group Types
! Enumeration for PID WindupMask.
!
! @b See also
! @classlink PID pwrb_pid.html
!*/
Object WindupMaskEnum $TypeDef 75
Body SysBody
Attr TypeRef = "pwrs:Type-$Enum"
Attr PgmName = "WindupMaskEnum"
EndBody
!/**
! Integral part only
!*/
Object IWUP $Value
Body SysBody
Attr PgmName = "IWUP"
Attr Text = "I"
Attr Value = 1
EndBody
EndObject
!/**
! Bias and Integral part
!*/
Object BIWUP $Value
Body SysBody
Attr PgmName = "BIWUP"
Attr Text = "BI"
Attr Value = 2
EndBody
EndObject
!/**
! Bias, Integral and Proportional part
!*/
Object BPIWUP $Value
Body SysBody
Attr PgmName = "BPIWUP"
Attr Text = "BPI"
Attr Value = 4
EndBody
EndObject
!/**
! All parts of the controller are limited in OutWindup
!*/
Object BPIDWUP $Value
Body SysBody
Attr PgmName = "BPIDWUP"
Attr Text = "BPID"
Attr Value = 8
EndBody
EndObject
EndObject
EndSObject
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment