EPICS记录参考--计算输出记录(calcout)

计算输出或"Calcout"记录类似于Calc记录,其增加了能够输出的特性(一个"output link"和一个"output event"),根据计算结果条件地执行它们。这种特性允许在一个EPICS数据库内实现了条件分支(例如:只在Record_B有一个0值时才运行Record_A)。Calcout记录也类似于Wait记录,但使用EPICS标准INLINK和OUTLINK字段而不是在Wait记录中使用的DBF_STRING字段。对于新的数据库,推荐使用Calcout记录替代Wait记录。

参数字段

在下面描述记录特定的字段,按功能分组。

扫描参数

Calcout记录有用于指定在什么情况下运行这个记录的标准字段。这些字段在Scan Fields中列出。

用于读取的参数

Calcout记录的读取参数由12个输入链接INPA, INPB,..., INPL组成。这些字段可以是数据库链接、通道访问链接或者常数。如果它们是链接,它们必须指定另一个记录的字段。如果它们是常数,用它们被配置的值初始化它们,并且可以通过dbPuts被更改。

这些字段不能是硬件地址。此外,Calcout记录包含INAV,INBV, ..., INLV字段,它们指明了链接字段的状态,例如,指定的PV是否被找到以及是否建立了指向它的链接。

表达式

像Calc记录一样,Calcout记录有一个CALC字段,开发者能够在其中输入一个内嵌表达式,在这个记录例程运行这个记录时,其将计算这个表达式。产生的值被放入VAL字段。这个值可以接着被OOPT字段使用来确定是否写到输出链接或者提交一个输出事件。它也可以时被写到输出链接的值。CALC表达式实际被转换为操作码并且以逆向Polish标记形式存储在RPCL字段。它是实际用于计算VAL的表达式。在运行时计算逆向Polish表达式比一个内嵌表达式效率更高。CALC可以在运行时被更改,并且一个special记录例程将调用一个函数去转换它为逆向Polish标记。

可以使用的内嵌表达式非常类似于C表达式语法,但在操作含义以及优先级中有写增加以及细微差别。字符串可以包含一系列由分号字符';'分隔的表达式,其中任何一个表达式可以实际提供计算结果;但包含的所有别的表达式必须把它们的结果赋给一个变量。以下描述的所有字母元素都是大小写无关的,因此在变量和函数名中根据需要可以使用和混合大小写字母。除了在组成单个表达式元素的字符之间,在一个表达式中任何地方可以使用空格。

这个计算记录支持的表达式范围被分为文字,常数,操作数,代数操作符,三角操作符,关系操作符,逻辑操作符,赋值操作符,括号和逗号,以及问号或"?:"操作符。

 文字

  • 标准双精度浮点数值
  • Inf:无限
  • Nan:非数值

常数

  • PI:返回数学常数PI
  • D2R:计算为PI/180,当用作乘数时,把一个角度从度转成弧度
  • R2D:计算为180/PI,当用作乘数时,把一个角度从弧度转成度

操作数

表达式可以使用从INPx链接获取的值作为操作数,虽然常数也可以用作操作数。从输入链接获取的这些值被存储在A-L字段。要在表达式中使用的值是由这个字段字母的简单引用。例如,从INPA获取的值被存储在字段A,而从INP链接获取的值被存储在字段B。在表达式中包含的名称将操作它们各自的值,诸如A+B。

 关键字VAL返回表达式的结果字段的当前内容,即:VAL字段对应CALC表达式,而OVAL字段对应OCAL表达式。(可以通过CA put写这些字段,所以它会不是从上次计算这个表达式的结果)。

代数操作

  • ABS:绝对值(单元)
  • SQR:平方根(单元)
  • MIN:最小(任意参数数目)
  • MAX:最大(任意参数数目)
  • FINITE:如果没有参数是NaN或Inf(任意参数数目),返回非零。
  • ISNAN:如果参数中有任意参数是NaN或Inf(任意参数数目),返回非零。
  • CEIL:上取整(单元)
  • FLOOR:下取整(单元)
  • LOG:以10为底的对数(单元)
  • LOGE:自然对数(单元)
  • LN:自然对数(单元)
  • EXP:指数函数(单元)
  • ^:指数(二元)
  • **:指数(二元)
  • +:加法(二元)
  • -:减法(二元)
  • *:乘法(二元)
  • /:除法(二元)
  • %:模(二元)
  • NOT:取反(单元)

三角运算符

  • SIN:正弦
  • SINH:双曲正弦
  • ASIN:反正弦
  • COS:余弦
  • COSH:双曲余弦
  • ACOS:反余弦
  • TAN:正切
  • TANH:双曲正切
  • ATAN:反正切

关系运算符

  • >=:大于或等于
  • >:大于
  • <=:小于或等于
  • <:小于
  • #:不等于
  • =:等于

逻辑操作符

  • &&:与
  • ||:或
  • :非

位操作符

  • |:位或
  • &:位与
  • OR:位或
  • AND:位与
  • XOR:位异或
  • ~:取反
  • <<:算术左移
  • >>:算术右移
  • >>>:逻辑右移

赋值操作符

  • :=:赋一个值(右手边)给一个变量(即:字段)

括号,逗号和分号

支持开和闭括号。支持嵌套的括号。

当用于分隔一个二元函数的参数时,支持逗号。

分号用于分隔表达式。虽然只允许一个传统的计算表达式,单允许多个赋值表达式。

条件表达式

支持C语言的问号运算符。格式是:condition? True result : False result;

表达式示例

算术

A + B + 10

结果是A + B + 10

关系

(A + B) < (C + D)

  • 如果(A + B) < (C + D),结果是1
  • 如果(A + B) >= (C + D),结果是0

问号

(A + B) < (C + D) ? E : F + L +10

  • 如果(A + B) < (C + D),结果是E
  • 如果(A + B) >= (C + D),结果是F+L+10

在base 3.14.9前,忽略:和条件的第二个部分是合法的,就像这样:

(A + B) < (C + D) ? E

  • 如果(A + B) < (C + D),结果是E
  • 如果(A + B) >= (C + D),结果不变。

从3.14.9以后,这个表达式应该被写成(A + B) < (C + D) ? E : VAL

逻辑

A & B

使得以下发生:

  • 转换A为整数
  • 转换B为整数
  • A和B进行位与
  • 转换结果为浮点数

赋值

sin(a) ; a:=a+D2R

使得Calc记录1度间隔输出一条正弦曲线的连续值。

输出参数

这些参数指定和控制Calcout记录的输出功能。它们确定何时写输出,向何处写输出,以及输出将是什么。OUT链接指向这个结果将被写到哪个过程变量。

菜单calcoutOOPT

OOPT字段确定使得向输出链接进行写的条件。其菜单有6个选项:

  •  Every Time:在每次运行记录时写输出。
  • On Change:每次VAL变化时,写输出,即:每次由于表达式的结果变化。
  • When Zero:当记录运行时,如果VAL是0,写输出。
  • When Non-zero:当记录每次运行时,如果VAL是非0,写输出。
  • Transition To Zero:当记录运行时,只在VAL时0并且上个值为非0时,写输出。
  • Transition To Non-zero:当记录运行时,只在VAL是非零并且上个值为0时,写输出。

菜单calcoutDOPT

DOPT字段确定了当执行输出时什么数据被写到输出链接。这个字段时一个有两个选项的菜单字段:

如果指定了Use CALC,当这个记录写它的输出时,它将写在CALC字段中表达式的结果,即是,它将这VAL字段的值。如果指定Use OCAL,这个记录将写在OCAL字段中表达式的结果,在OVAL字段中包含这个结果。OCAL字段完全类似CALC字段,并且有相同功能,它可以包含一个在运行时计算的表达式的字符串表示。因而,如果需要,这个记录可以使用CALC表达式的结果来确定数据是否应该被写并且可以使用OCAL表达式的结果作为要写的数据。

如果OEVT字段指定一个非0整数并且满足在OOPT中的条件,这个记录将提交一个对应的事件。如果ODLY字段是非0,在执行OUT链接或者提交这个输出事件前,这个记录暂停指定的秒数。在这段等待期间,这个记录是"活动的",并且在等待结束前将不再被运行。在延时期间,字段DLYA等于1。延时入口系统的分辨率系统相关。

IVOA字段指定了如果Calcout记录进入一个INVALID警报状态时对OUT链接采取什么动作。这些操作是Continue normally, Don't drive outputs和Set output to IVOV。如果IVOA字段是Set output to IVOV,如果记录警报严重性是INVALID,输入到IVOV字段的数据被写到了OUT链接。

操作显示参数

 这些参数用于显示有意义数据到操作者。一些用于在运行时显示这个记录的状态。

EGU字段包含一个由用户提供的最长16个字符的字符串,其描述正在操作的值。在调用例程get_units()时,获取这个字符串。EGU字符串是唯一用于操作者并且不是必须被使用。

HOPR和LOPR字段仅指向VAL,HIHI,HIGH,LOW和LOLO字段的限制。PREC控制VAL字段的精度。

菜单calcoutNAV

INAV-INLV字段各自指定在INPA-INPL字段中指定的指向PVs链接的状态。这些字段可能有四个可能的值:

  • Ext PV NC:在这个IOC上没有找到这个PV以及一个通道访问链接还未被建立。
  • Ext PV OK:在这个IOC上没有找到这个PV以及一个通道访问链接已经被建立。
  • Local PV:在这个IOC上找到这个PV。
  • Constant:相应的链接字段是一个常数。

OUTV字段指明OUT链接的状态。它有与INAV-INLV字段相同可能的值。

CLCV和OLCV字段各自指明在CALC和OCAL字段中表达式的有效性。如果表达式无效,这个字段被设置为1。在ODLY中指定的延时期间,DLYA字段被设为1。

有关记录名(NAME)和描述(DESC)字段更多信息见Fields Common to All Record Types。

警报参数

 calcout记录的可能警报条件是SCAN,READ,计算以及限制警报。SCAN和READ警报被记录支持程序调用。当CALC表达式是一个无效表达式时,对这个表达式产生一条错误消息,计算警报被记录process例程调用。

以下警报参数,由用户配置,定义VAL字段的限制警报以及对应那些情况的严重性。

HYST字段为每个限制定义一个警报死区。

记录警报和标准字段的完整解释见Alarm Specification。Alarm Fields列出了所有记录类型都有的警报相关联的其它字段。

监控参数

 这些参数用于确定何时发送这个值字段的monitors。当这个值字段超过了上次受监视字段合适死区时,发送这些monitors。ADEL用于存档monitors,而MDEL字段用于所有其它类型monitors。如果这些字段有一个0值,每次这个值变化时,触发monitors;如果它们有一个-1值,每次扫描这个记录时,触发monitors。

运行时参数

 这些字段不是使用配置工具配置的,并且在运行时都不可修改。它们用于运行这个记录。

LALM字段用于实现警报限制的回滞因子。

LA-LL字段用于决定何时触发相应字段的monitors。例如,如果LA不等于A的值时,触发A的monitor。MLST和ALST字段以对应VAL字段相同方式被使用。

记录支持

 记录支持例程

1) init_record

对于每个常数输入链接,如果输入链接是CONSTANT,用这个常数值初始化相应的值字段或者如果这个链接是PV_LINK,创建一个通道访问链接。

一个例程postfix被调用转换在CALC和OCAL中的内嵌表达式为反向Polish标记。结果各自被存储在RPCL和ORPC。

2) process

见下部分。

3) special

如果CALC或OCAL被更改,调用这个例程。special调用postfix。

4) get_units

获取EGU。

5) get_precision

获取精度。

6) get_graphic_double

为一个字段设置上显示和下显示限制。如果字段是VAL,HIHI,HIGH,LOW或LOLO,这些限制被设置HOPR和LOPR,否则如果这个字段有定义的上和下限制,使用它们,否则将使用对应这个字段类型的上和下最值。

7) get_control_double

为一个字段设置上控制和下控制限制。如果字段是VAL,HIHI,HIGH,LOW或LOLO,这些限制被设置HOPR和LOPR,否则如果这个字段有定义的上和下限制,使用它们,否则将使用对应这个字段类型的上和下最值。

8) get_alarm_double

设置以下值:

upper_alarm_limit = HIHI
upper_warning_limit = HIGH
lower warning_limit = LOW
lower_alarm_limit = LOLO

记录运行

process()

 process()例程实现以下算法:

1、获取所有参数。

2、调用例程calcPerform(),它从在CALC中给出表达式的前缀版本计算VAL。如果calcPerform()返回成功,UDF被设置成False。

3、检查警报。这个例程检查新的VAL是否引起警报状态和严重性变化。如果这样,NSEV,NSTA和LALM被设置。它也遵守警报回滞因子(HYST)。因而,在警报状态和严重性变化前,这个值必须至少变化HYST。

4、确定是否满足输出执行选项(OOPT)。如果满足,要么(如果ODLY=0)执行输出链接(和输出事件)或者在指定间隔后调度一个回调。见以下execOutput()例程的解释。

5、检查是否应该调用monitors。

  • 如果警报状态或严重性变化了,调用警报monitors。
  • 如果满足ADEL和MDEL条件,调用存档和值变化monitors。
  • 当其它monitors被调用了,检查A-L的monitors。
  • 重置NSEV和NSTA为0。

6、如果没有指定输出延时,如果需要,扫描forward链接,设置PACT为FALSE,并且返回。

execOutput()

1) 如果DOPT字段指定使用OCAL,为在OCAL中表达式的后缀版本调用例程calcPerform()。否则,使用VAL。

2) 如果警报严重性是INVALID,按照字段IVOA指定的选项。

3) 警报严重性不是INVALID或者IVOA制定了"Continue Normally",把OVAL的值放入OUT链接并且提交OEVT(如果非零)中的事件。

4) 如果实现了一个输出延时,运行forward链接。

示例:

1) 建立一个以下数据库:

  • $(USER):Int1和$(USER):Int2记录实例的记录类型是longin, 通过通道访问caput向它们写数据并且它们作为$(USER):Calcout记录的两路输入,它们的运行会引起$(USER):Calcout记录运行。
  • $(USER):Calcout记录实例的记录类型是calcout,根据字段DOPT是"Use CALC"或"USE OCAL"选择运行CALC或OCAL中的表达式,并且输出VAL或OVAL的值到$(USER):Float记录实例。
  • $(USER):Float记录实例的记录类型是ai,获取$(USER):Calcout记录实例的计算结果。
  • $(USER):Count记录实例的记录类型是calc,它记录$(USER):Calcout记录实例运行的次数。
record(longin, "$(USER):Int1")
{
        field(SCAN, "Passive")
        field(INP, "10")
        field(DTYP, "Soft Channel")
        field(FLNK, "$(USER):Calcout")
}


record(longin, "$(USER):Int2")
{
        field(SCAN, "Passive")
        field(INP, "5")
        field(DTYP, "Soft Channel")
        field(FLNK, "$(USER):Calcout")
}

record(calcout, "$(USER):Calcout")
{
        field(SCAN, "Passive")
        field(INPA, "$(USER):Int1")
        field(INPB, "$(USER):Int2")
        field(CALC, "A + B")
        field(OCAL, "A - B")
        field(OEVT, "1")
        field(OUT, "$(USER):Float")
        field(OOPT, "On Change")
        field(DOPT, "Use CALC")
}

record(ai, "$(USER):Float")
{
}



record(calc, "$(USER):Count")
{
        field(SCAN, "Event")
        field(EVNT, "1")
        field(INPA, "$(USER):Count.VAL")
        field(CALC, "A + 1")
}

2) 将以上数据库实例化,获取以下的记录:

epics> dbl
blctrl:Calcout
blctrl:Int1
blctrl:Int2
blctrl:Count
blctrl:Float

 3) 零开一个终端,用通道访问命令进行测试:

[root@bjAli ~]# caget blctrl:Count
blctrl:Count                   0
[root@bjAli ~]# caput blctrl:Int2 30
Old : blctrl:Int2                    5
New : blctrl:Int2                    30
[root@bjAli ~]# caget blctrl:Count
blctrl:Count                   1
[root@bjAli ~]# caget blctrl:Float                    # 使用了A+B
blctrl:Float                   40
[root@bjAli ~]# caput blctrl:Calcout.DOPT "Use OCAL"  # 从使用CALC中表达式切换到使用OCAL中表达式
Old : blctrl:Calcout.DOPT            Use CALC
New : blctrl:Calcout.DOPT            Use OCAL
[root@bjAli ~]# caget blctrl:Float              
blctrl:Float                   40
[root@bjAli ~]# caput blctrl:Int1 38                  # 使用了A-B
Old : blctrl:Int1                    10
New : blctrl:Int1                    38
[root@bjAli ~]# caget blctrl:Float
blctrl:Float                   8
[root@bjAli ~]# caget blctrl:Count
blctrl:Count                   2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值