#define ALARM_MAX_NUM 128
#define Device_MAX_NUM 64
#define Analog_MAX_NUM 256
#define Status_MAX_NUM 128
//以上宏定义是为了方便修改参数,并提高程序的可移植性
extern SEvent Alarm[ALARM_MAX_NUM];
extern SDev Device[Device_MAX_NUM];
extern SAnalog Analog[Analog_MAX_NUM];
extern SStatus Status[Status_MAX_NUM];
说明:
这里实例化得到的是数组。为了简化起见,各类数据都固定大小数组来管理,实际工程中应是动态的。
3.2 系统算法
系统算法结构如图3.1:
图3.1 系统算法结构图
说明:
(1)初始化时需要完成两个工作:
a、从外部文件将预设的模拟量、状态量和设备的配置参数读进内存;
b、初始化语音合成引擎。
(2)人机界面通过用edit box、list control等控件以添加变量的方式实时显示数据。
(3)数据来源于仿真,仿真得到的值写入在内存中定义的结构体数组内。
(4)在内存中,将实时数据(数组元素)的值与预先写入的参数比较,判断出设备的状态,若为正常,数组指针加1后进入下一循环。若为告警状态,则生成告警事件,在内存中写入告警事件结构的数组中,等待播报及写入文件保存。
(5)初始化完成后,语音合成函数则有效。可以被调用对告警事件进行播报。
(6)运行中的各项数据,均需要在外部文件中保存,以方便查阅。包括定时保存的实时运行数据和实时保存的告警事件信息。
3.3 程序结构
3.3.1 算法实现
由于语音播报、读写文件操作和读写内存操作所需要的时间长短有较大的差别,但监控系统又需要保证很高的实时性,所以上述系统结构无法用简单的单线程操作完成。所以在实现时,添加多条线程及其服务程序,通过修改线程标志来控制。但同时要注意控制各线程之间协调运行,防止出现数据混乱的现象。
按照上述算法结构,编写程序,具体如图3.2:
图3.2 告警事件生成程序结构框图
说明:
(1)除了主线程外,再建立四条线程:
a、数据实时仿真线程,控制标志(Flag_Simulate)由人机界面上“开始仿真”启动,“停止仿真”按钮关闭或挂起;
b、语音播报线程,控制标志(Flag_Speech)由人机界面上“启动语音”按钮启动,“关闭语音”按钮关闭或挂起;
c、告警事件保存线程,始终运行直到程序退出,保证实时记录下所有告警事件。
d、实时数据保存线程,用于定时保存运行历史数据。在这个模拟的系统中,只有当仿真开始后才会产生运行数据,才需要运行该线程来实时保存运行数据。所以,该线程与实时仿真线程使用同一个标志。
3.3.2 告警管理
在前文中提到,添加三个线程的原因,是因为语音播报、读写文件操作和读写内存操作所需要的时间长短有较大的差别。那么,在线程中,又该怎么做才能保证做到异步读写有序的进行呢?由于三个线程的解决方法相同,所以下面只取语音播报线程为例,进行关于告警管理的讨论。
由于对数据结构实例化得到的数组成员是有限的,且对成员的顺序操作是循环刷新的方式,但这就会出现一个问题。下面举例说明:
实例化后的数组Alarm[],用于记录生成的告警事件。本程序中,该数组有128个成员。程序将告警事件写入Alarm[]时,是自上而下的,即数组标志逐一增加。当Alarm[127]写入完成后,重新从Alarm[0]开始,并将之前内存中的内容冲掉。
语音播报Alarm[]中内容也是这种方式。但为防止播报时出现重复播报、多语音播报、漏报、播报中断等情况出现,语音采用采用顺序播报模式,即播报完当前语句后才报下一句。(具体播报模式如何实现详见x.x4.4) 35kV变电站监控系统中告警事件生成与语音告警软件设计(9):http://www.751com.cn/zidonghua/lunwen_7940.html