JZGKCHINA
工控技术分享平台
尊重原创 勿抄袭
勿私放其他平台
在剑指工控群里,一群友问PLC如何产生随机数,曾记得除了三菱PLC之外其他常规品牌好像没有提供专门的随机函数。这里就整理两种产生随机数的方法:
第一种最简单直接的方法。
此方法使用的是读取CPU系统时间的纳秒作为随机数。如下图:
纳秒的位数越多随机数越无规律。
第二种用得较多的是“线性同余法"
就是下面这个式子
R(n 1) = [R(n) * a b] mod c
为使随机数分布尽量均匀,a、b 均为质数, c 一般取值域内的最大值(mod 是求余数)
从这个式了可以看出,每次产生的随机数都跟上一次产生的数有关系,那么,第一个数是怎么来的呢?这就是线性同余法中必须用的的”种子",也就是说,给定某个种子后,所产生的随机数序列是固定的,在计算机编程中,一般使用系统时间来初始化种子,就是前面代码中的 srand((unsigned)time(NULL)); 这一句了。因为每次运行程序的时间肯定不一样,所以产生散列肯定也不一样,从而达到“随机”的目的。
a,b,c 的取值我用的是 a=3373, b=1, c=32768
两个子程序
下面的两个子程序是smart 200中产生随机的系统编号用的,因为编号中只有4位数采用了随机数,所以下面的程序中用的是整型,最大范围为32767。如果需要更宽范围的随机数,可以采用双字类型,并适当修改程序。
使用时在第一个扫描周期调用 Srand 初始种子,需要随机数的地方调用 Random
Random 有了个最大范围参数,可以限制生成的随机数的最大范围,比如我只需要4位随机数,所以一般这样调用 CALL Random, 10000, vw0,生成的数就在 0-9999 范围内
下面是代码:
SUBROUTINE_BLOCK Srand:SBR17
TITLE=初始化随机数种子
//
// 直接使用系统时钟的分秒来作为种子
VAR_OUTPUT
seed:WORD;
END_VAR
BEGIN
Network 1
LD SM0.0
TODR VB1990
Network 2
LD SM0.0
BTI VB1994, AC1
SLW AC1, 8
BTI VB1995, AC3
I AC3, AC1
MOVW AC1, LW0
END_SUBROUTINE_BLOCK
SUBROUTINE_BLOCK Random:SBR16
TITLE=随机数发生器
//
// 线性同余法获取伪随机数,范围:0~32767
//
// seed = (seed * 3373 1) % 32768;
//
VAR_INPUT
wMax:WORD; // 最大范围
END_VAR
VAR_OUTPUT
wOut:WORD;
END_VAR
BEGIN
Network 1
// wSeed * 3373 1 => AC1
LD SM0.0
ITD VW1940, AC1
*D 3373, AC1
INCD AC1
Network 2
// AC1 mod 32768 => wSeed
LD SM0.0
MOVD AC1, AC3
/D 32768, AC3
*D 32768, AC3
-D AC3, AC1
DTI AC1, VW1940
Network 3
// wSeed / 32768 * wMax => wOut
LD SM0.0
DTR AC1, AC1
/R 32768.0, AC1
ITD LW0, AC3
DTR AC3, AC3
*R AC3, AC1
ROUND AC1, AC1
DTI AC1, LW2
END_SUBROUTINE_BLOCK
作 者 简 介
曹俊义
工业物联网资深构建专家
工厂智能化改造践行专家
资深工业网络通讯专家
工业自动化控制系统专家
ProSoft产品顶级技术专家
工业通讯领域沉浸十数年,深喑各种工业通讯协议和工业网络架构以及国内外多种主流PLC应用和操作、熟知罗克韦尔、施耐德、西门子、GE等知名品牌的冗余系统,对工业无线通讯、工业物联网、工业IT与OT的融合,有着前瞻性的独到见解和务实的实践经验。
现任伟联科技董事长。努力为中国工业信息化、数字化、智能化的深入发展做出贡献。