• {{item.name}}
{{item.name}}
{{item2.name}}
更多
操作指南

比较实际趋势曲线和设定值(理想)曲线的实现方法

star star star star star
5.0 分
  • 系统配置
  • SIMATIC WinCC Basic
文档编号:A0464| 文档类型:操作指南| 发布时间:2024年02月19日
  • 0
  • 418
  • 6933
在某些情况下(例如:绘制温度、压力或位置曲线时),用户需要将实际的趋势曲线跟设定值(理想)曲线同时显示在趋势图中进行比较。本文介绍了如何使用WinCC的“函数趋势控件“和“用户归档“实现以上的需求。

1概述
同时将实际的趋势曲线和设定值(理想)曲线显示在趋势图中,可以方便客户进行比较,运行时的效果如图1所示。在“函数趋势控件“上,横坐标代表绘制的点的序号,按照时间序列从左到右依次排列,纵坐标代表变量值。本例中每隔1秒钟读取一次变量值。图1中红色曲线代表理想曲线,根据一组设定值绘制,理想趋势的数值必须保持在用户归档中;蓝色曲线代表实际的趋势曲线,根据各个时刻变量的实际值绘制。


图1 实际趋势曲线和理想曲线的比较

2用户归档的组态

2.1 使用用户归档存放曲线的设定值
新建用户归档,名称为“CompareSetPoint”,用于存放理想曲线的各个设定值。插入两个域,域“PointNumber”对应于“函数趋势控件”横坐标的点的序号,本例中为0到9。域“SetValue”对应于“函数趋势控件”纵坐标的相应点的设定值。用户归档表格“CompareSetPoint”的值由用户在组态时设定即可,如下图所示:


图2 用户归档的设定值表

2.2 使用用户归档存放曲线的实际值
新建用户归档,名称为“CompareActualValue “,用于存放实际曲线的各个变量值。插入两个域,域“PointNumber”对应于“函数趋势控件”横坐标的点的序号,本例中为0到9。域“ActualValue”对应于“函数趋势控件”纵坐标的相应点的实际变量值。用户归档表格“CompareActualValue”的值在WinCC运行时,由实际的变量值进行填充。

3 函数趋势控件的组态
从“对象选项板 “中的“控件”页中,将“WinCC Function Trend Control”托拽到画面上进行设置。

3.1 如何组态设定值曲线
1. 双击函数趋势控件,单击“曲线”标签,选中“设定值趋势”复选框。单击“属性...”按钮,打开“设定值趋势的属性”对话框。


图3 “设定值趋势的属性”对话框

2. 在“归档连接”的“源”中,使用标记有“...”的按钮,并选择用户归档“CompareSetPoint”。在“X 轴数值的列”中,选择“PointNumber”;
在“Y 轴数值的列”中,选择“SetValue”。为了定义希望显示的时间范围,可指定所要表示的数值对的数目10,以及第一个数值对的 ID 号1。选择用于设定趋势的颜色“红色”,显示类型为“带虚线的连接点”。单击“确定”关闭对话框,并保存设置。

3.2 如何组态实际曲线
1. 单击“曲线”标签,组态实际曲线的“颜色”、“显示类型”和“线条粗细”,本示例中设置为“蓝色”。

2. 单击“数据连接”标签,在“提供者”中选择“用户归档”,在“用户归档”的“源”中选择“CompareActualValue”。在“X 轴数值的列”中,选择“PointNumber”;在“Y 轴数值的列”中,选择“ActualValue”列。将“成对数值的数目“设为10,“从ID”设置为1。


图4 “数据连接”标签的参数设置

3. 单击“X轴”标签, 将“粗略定标”设置为1,取消“精细定标“复选框,将“小数位”和“标尺的小数位”都设为0。取消“自动”复选框,设置值范围从0到9。“Y轴”标签和“X轴”标签设置相同。点击“确定”按钮,保存“函数趋势控件”的属性设置。


图5 “X轴”标签的参数设置


4 编写C脚本插入用户归档记录以绘制实际曲线
1. 新建两个内部变量“StartCompare”和“SimulateValueIndex“,类型均为“无符号16位数”。变量“StartCompare”用于启动实际变量的读取和曲线的绘制,变量“SimulateValueIndex“用于记录仿真数组的索引号,对应于实际的点数。

2. 设计一个全局C动作“MakeActualTrend.pas”,用于生成实际的趋势曲线,触发周期设置为1秒钟,需要编写如下的脚本:
int pointNumber, actualValue;
int simulateValueArray[10] = { 1, 2, 3, 4, 5, 4, 3, 2, 1, 2 };
if ( GetTagBit("StartCompare") == TRUE )
{
pointNumber = GetTagWord("SimulateValueIndex");
actualValue = simulateValueArray[pointNumber ];

if( uaInsertRecords( "CompareActualValue", InsertJobCB, pointNumber, actualValue ) )
printf( "Insert point %d O.K. \r\n", pointNumber );
else printf( "Insert point %d failed ! \r\n", pointNumber );

pointNumber++;
if ( pointNumber >=10 )
{
pointNumber =0;
SetTagBit( "StartCompare", FALSE );
printf( "========== Insert point end ==========\r\n");
}
SetTagWord( "SimulateValueIndex", pointNumber );
}
数组simulateValueArray[10]中存放的是用于测试的仿真数据,该全局脚本每隔1秒钟执行一次,当发现“StartCompare”变量为“TRUE“时,按照每隔1秒钟的周期,依次将仿真数组中的数据和数组的索引写入到用户归档表格“CompareActualValue“中,10个数据都写完后,将“StartCompare”变量置为“FALSE“。注意,在实际的项目中,用户可以根据需求,按照指定的周期从实际的设备变量中取值。此外,在“计算机属性”的“启动”列表中,需要勾选“全局脚本运行系统”。上述代码编译时提示“函数uaInsertRecords未定义”,下面新建一个项目函数“uaInsertRecords”,实现向用户归档中插入数据的功能,代码如下:
#include "apdefap.h"
BOOL uaInsertRecords(const char* pszArchiveName ,
BOOL (UserFunc) (UAHARCHIVE* phUA, int pointNumber, int actualValue), int pointNumber, int actualValue )
{
BOOL returnCode = TRUE;
const char* funcName = "uaInsertRecords" ;
UAHCONNECT hConnect ;

// Get Connection to User Archives
returnCode = uaConnect( &hConnect );
if( !returnCode || !hConnect)
{
returnCode = FALSE;
printf( "#E110:%s fault in uaConnect \r\n", funcName );
}
else
{
// Get Handle to Actual Archive.
UAHARCHIVE hArchive;
if(! uaQueryArchiveByName( hConnect, pszArchiveName , &hArchive ))
{
printf( "#E210:%s: uaQueryArchive Error: %d\r\n", funcName , uaGetLastError());
returnCode = FALSE;
}
else
{
// Open data returned by query.
if(uaArchiveOpen(hArchive))
{
// Delete all the archive records if restart to compare.
if ( pointNumber == 0 )
{
returnCode = uaArchiveDelete( hArchive, "" );
if ( !returnCode )
{
printf("#E:%s error uaArchiveDelete\r\n", funcName );
}
}

returnCode = uaArchiveRequery(hArchive);
if (!returnCode )
{
printf("#E322:%s error UAArchiveRequery\r\n", funcName );
}

// Insert the value to user archive table.
returnCode = UserFunc(&hArchive, pointNumber, actualValue);
if(!returnCode )
{
printf("#E340:%s error in User Funcion !! \r\n ", funcName);
}

// Close the archive.
if (!uaArchiveClose (hArchive ))
{
printf("E810:%s error in uaArchiveClose ! \r\n ",funcName) ;
returnCode = FALSE ;
}
}
else
{
printf("#E820:%s error in uaArchiveOpen! \r\n ", funcName);
returnCode = FALSE;
}
if(!uaReleaseArchive (hArchive))
{
printf("#E830:%s error in uaReleaseArchive! \r\n ", funcName);
returnCode = FALSE;
}
}
if( !uaDisconnect(hConnect))
{
printf("#E840:%s error in uaDisconnect ! \r\n ", funcName);
returnCode = FALSE ;
}
}
return returnCode;
}
以上代码实现了如下的功能:
1. 建立到用户归档的连接。
2. 根据归档名称“CompareActualValue”获得用户归档的句柄。
3. 打开用户归档。
4. 如果重新开始比较,则删除表格中的所有数据。
5. 将当前变量的值和对应点的索引插入到用户归档表格中。
6. 关闭并释放用户归档。
7. 断开到用户归档的连接。
其中的UserFunc调用了项目函数“InsertJobCB”,实现插入数据到用户归档表格的功能。新建一个项目函数“InsertJobCB”,代码如下:
#include "apdefap.h"
BOOL InsertJobCB( UAHARCHIVE* phArchive , int pointNumber, int actualValue )
{
BOOL rc = TRUE; // Return code

if( ! uaArchiveSetFieldValueLong( *phArchive, 1, pointNumber) || // write productname to archive
! uaArchiveSetFieldValueLong( *phArchive, 2, actualValue ) ) // write number of parts to archive
{
printf( "InsertJobCB: error on writing to record \r\n" );
rc = FALSE ;
}
else
{
if( !uaArchiveInsert( *phArchive ) ) // insert new line in archive
{
printf( "InsertJobCB: error on updating archive \r\n" );
rc = FALSE ;
}
}
return rc;
}
以上代码将当前变量的值和对应点的索引值写入用户归档表格“CompareActualValue ”中。此时,再次编译全局C动作“MakeActualTrend.pas”,则编译成功。

3. 在画面上放置两个按钮“Start”和“Stop”,在按钮“Start”的“鼠标动作“中,添加C脚本,将“StartCompare”变量值设为“TRUE“,并将仿真数组的索引值设为0。
printf( "========== Insert point begin ==========\r\n");
SetTagBit( "StartCompare", TRUE );
SetTagWord( "SimulateValueIndex", 0 );

在按钮“Stop”的“鼠标动作“中,添加C脚本,将“StartCompare”变量值设为“FALSE“,并将仿真数组的索引值设为0。
printf( "========== Insert point end ==========\r\n");
SetTagBit( "StartCompare", FALSE );
SetTagWord( "SimulateValueIndex", 0 );


5需要注意的问题

1. 用户可根据实际的需求,通过脚本控制数据读取的逻辑。本例中利用全局动作脚本周期地读取变量值,由于所有的全局C动作位于同一个脚本队列中,因此如果还有其它的耗时的全局C动作在运行时,势必会影响实时曲线数据的周期采集,因此应尽量避免其它全局C动作的影响。如果希望采集周期尽可能准确,可以使用如下方法2:在画面上的“Start”按钮中使用脚本循环进行数据的采集,并插入到用户归档表格中,使用Sleep函数进行延时来控制时间间隔,由于这种方法在比较长的时间内独占了整个画面动作的脚本线程,只有该“Start”动作执行完成后,其他的画面动作才可以执行,因此使用时要慎重。

2. 本例中点击“Start”按钮后,并没有立即启动插入变量值到用户归档的过程,等到全局C动作执行到下一个周期后才开始启动插入的过程,其间有不到1秒钟的延时。如果希望点击“Start”按钮后立即执行,可以使用上述的方法2。如果用户对采集周期的精度有较高的要求,请对WinCC的脚本进行测试以确定是否可以达到客户的要求。

3. 附件中提供了完整的项目文件,是在WinCC V6.2 SP2版本中生成的。运行时点击“Start”或“Stop”按钮可以看到实际的效果。注意,本示例仅供用户参考使用。

关键词
趋势曲线、函数趋势控件、用户归档、比较、C脚本


您可以前往全球资源库查看此文档

剩余80%未阅读,请登录后下载/查看文档

  • 评论
更多
  • 分享

    扫码分享

提示
您即将前往“全球技术资源库”。
“全球技术资源库”的用户名与本地支持中心(下载中心、技术论坛、找答案、1847工业学习平台)的用户名不通用。如果需要在全球技术资源库下载文档,您需要重新登录或注册。
确定

扫码进入移动端

信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。