• 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

    设置以下值:

    1. upper_alarm_limit = HIHI
    2. upper_warning_limit = HIGH
    3. lower warning_limit = LOW
    4. 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记录实例运行的次数。
    1. record(longin, "$(USER):Int1")
    2. {
    3. field(SCAN, "Passive")
    4. field(INP, "10")
    5. field(DTYP, "Soft Channel")
    6. field(FLNK, "$(USER):Calcout")
    7. }
    8. record(longin, "$(USER):Int2")
    9. {
    10. field(SCAN, "Passive")
    11. field(INP, "5")
    12. field(DTYP, "Soft Channel")
    13. field(FLNK, "$(USER):Calcout")
    14. }
    15. record(calcout, "$(USER):Calcout")
    16. {
    17. field(SCAN, "Passive")
    18. field(INPA, "$(USER):Int1")
    19. field(INPB, "$(USER):Int2")
    20. field(CALC, "A + B")
    21. field(OCAL, "A - B")
    22. field(OEVT, "1")
    23. field(OUT, "$(USER):Float")
    24. field(OOPT, "On Change")
    25. field(DOPT, "Use CALC")
    26. }
    27. record(ai, "$(USER):Float")
    28. {
    29. }
    30. record(calc, "$(USER):Count")
    31. {
    32. field(SCAN, "Event")
    33. field(EVNT, "1")
    34. field(INPA, "$(USER):Count.VAL")
    35. field(CALC, "A + 1")
    36. }

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

    1. epics> dbl
    2. blctrl:Calcout
    3. blctrl:Int1
    4. blctrl:Int2
    5. blctrl:Count
    6. blctrl:Float

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

    1. [root@bjAli ~]# caget blctrl:Count
    2. blctrl:Count 0
    3. [root@bjAli ~]# caput blctrl:Int2 30
    4. Old : blctrl:Int2 5
    5. New : blctrl:Int2 30
    6. [root@bjAli ~]# caget blctrl:Count
    7. blctrl:Count 1
    8. [root@bjAli ~]# caget blctrl:Float # 使用了A+B
    9. blctrl:Float 40
    10. [root@bjAli ~]# caput blctrl:Calcout.DOPT "Use OCAL" # 从使用CALC中表达式切换到使用OCAL中表达式
    11. Old : blctrl:Calcout.DOPT Use CALC
    12. New : blctrl:Calcout.DOPT Use OCAL
    13. [root@bjAli ~]# caget blctrl:Float
    14. blctrl:Float 40
    15. [root@bjAli ~]# caput blctrl:Int1 38 # 使用了A-B
    16. Old : blctrl:Int1 10
    17. New : blctrl:Int1 38
    18. [root@bjAli ~]# caget blctrl:Float
    19. blctrl:Float 8
    20. [root@bjAli ~]# caget blctrl:Count
    21. blctrl:Count 2
  • 相关阅读:
    anaconda+pytorch安装+pycharm环境配置
    C语言【隐式类型转换】和【显式类型转换】
    react18 001
    BLUE引擎变量数据分析
    2024-06-24力扣每日一题
    第二篇 熊猫烧香之行为分析
    数据结构-leetcode-数组形式的整数加法
    最大正方形的边长长度问题解法
    如何搭建一个好看的github主页
    JavaWeb之组件Servlet详解
  • 原文地址:https://blog.csdn.net/yuyuyuliang00/article/details/127849349