2019年11月13日
Thingworx中的SPC计算工具
Thingworx提供了两个SPC计算工具: StatisticalCalculationThingShape,和StatisticalMonitoringThingShape,但前提条件是需要DescriptiveAnalytics平台。
大致步骤是:
1. 购买安装DescriptiveAnalytics。
2. 建立Thing,配置Data Shape和Value Stream,设置数值属性logged。
3. 调用StatisticalCalculationThingShape.QueryTimedValuesForProperty生成TimedValues类型的InfoTable。
4. 调用StatisticalCalculationThingShape.CalculateMeanValue等函数生成具体的SPC数值。
这种方式适用于工艺参数采集,即Thing和Property均已事先定义的情况下。
如果不采用DescriptiveAnalytics平台,或者说数据不适合用Value Stream记录(比如直接从拧紧枪数据库查询数据),那么就需要自己计算SPC了。
具体步骤为:
1. 经由数据库查询等方式生成InfoTable类型的数据集。
2. 调用infotable for loop方法,逐行读取并分析数据,计算最大值、最小值、平均值。
3. 利用数组暂存数据,然后读取数组,计算标准方差。不用数组的话,也可以将InfoTable重新读取一次。
4. 输出InfoTable类型的数据集。
以下是参考代码:
------------------------------------------------
// Get USL&LSL
var USL = spcTable.rows[0].USL;
var LSL = spcTable.rows[0].LSL;
//logger.info("USL="+USL);
//logger.info("LSL="+LSL);
// Get Sum
var sum = 0.0;
var spc1 = []; // array of spc1
var tableLength = spcTable.rows.length;
//logger.info("tableLength="+tableLength);
for (var x=0; x < tableLength; x++) {
var row = spcTable.rows[x];
spc1[x] = row.SPC1;
//logger.info("spc1="+row.SPC1);
sum = sum + row.SPC1;
}
//logger.info("x="+x);
//logger.info("sum="+sum);
//var result = sum;
// Get Average
var u = sum / tableLength;
//logger.info("u="+u);
// Get SD
var sd = 0;
for (x=0; x < tableLength; x++) {
sd = sd + (spc1[x]-u) * (spc1[x]-u);
}
sd = sd/(tableLength-1);
sd = Math.sqrt(sd);
//logger.info("sd="+sd);
// Get CPU
var cpu = (USL-u)/(3*sd);
//logger.info("cpu="+cpu);
// Get CPL
var cpl = (u-LSL)/(3*sd);
//logger.info("cpl="+cpl);
// Get CPK
var cpk = 0;
if(cpu < cpl) {
cpk = cpu;
} else {
cpk = cpl;
}
//logger.info("cpk="+cpk);
// Output data
var params = {
infoTableName : "InfoTable",
dataShapeName : "DS_SPC_CPK_OUT"
};
// CreateInfoTableFromDataShape(infoTableName:STRING("InfoTable"), dataShapeName:STRING):INFOTABLE(DS_SPC_CPK_OUT)
var spcOut = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape(params);
spcOut.AddRow({Sum:sum, Avg:u, SD:sd, USL:USL, LSL:LSL, CPU:cpu, CPL:cpl, CPK:cpk, Qty:tableLength});
var result = spcOut;
------------------------------------------------
2019年11月4日
关于SQL SERVER的两个备忘
最近在用SQL SERVER做数据的后台自动处理,然后利用Thingworx展现。
这其中碰到两个问题,觉得较有代表性,在此做个备忘。
1. 关于游标内调用其它游标
我之前做过很多项目采用ORACLE数据库,其动态游标、物化视图、数组的功能非常NB,给我留下了深刻的印象。
但是我没想到在使用SQL SERVER游标时却踩到了坑。
SQL SERVER有一个全局变量@@FETCH_STATUS用来表示游标的状态,0表示尚未结束,-1表示已结束。
但是关键@@FETCH_STATUS是全局变量,这就意味着当第一个游标尚未结束时,当第二个游标的状态=-1时,也会将第一个游标强行结束。
解决的办法是用一个本地的变量,把@@FETCH_STATUS的值赋给此变量后再进行检查。
但是此办法逻辑上并不完备,如果有大量的并发,则可能会造成冲突。
因此如果需要配置后台任务,应该尽可能在时间上分散开来,以避免并发。
下面是相关的参考代码:
---------------------------------------------------------------------------
-- Normally, we use system variable @@FETCH_STATUS to check Cursor loop
DECLARE myCursor CURSOR FOR
SELECT fields FROM Table;
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @myVar;
WHILE @@FETCH_STATUS = 0
BEGIN
--DO somthing;
END
CLOSE myCursor;
DEALLOCATE myCursor;
-- But @@FETCH_STATUS is global variable
-- So if we use another Cursor within the loop, when inner loop is completed, @@FETCH_STATUS = -1, so the outer loop will also be closed.
-- Fixing method is to use local variable instead of @@FETCH_STATUS
DECLARE myCursor CURSOR FOR
SELECT fields FROM Table;
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @myVar;
SET @Outer_loop = @@FETCH_STATUS;
WHILE @Outer_loop = 0
BEGIN
--inner loop here
DECLARE myCursor2 CURSOR FOR
SELECT fields FROM Table2;
OPEN myCursor2;
FETCH NEXT FROM myCursor2 INTO @myVar2;
SET @Inner_loop = @@FETCH_STATUS;
WHILE @Inner_loop = 0
BEGIN
--Inner loop function
FETCH NEXT FROM myCursor2 INTO @myVar2;
SET @Inner_loop = @@FETCH_STATUS;
END
CLOSE myCursor2;
DEALLOCATE myCursor2;
FETCH NEXT FROM myCursor INTO @myVar;
SET @Outer_loop = @@FETCH_STATUS;
END
CLOSE myCursor;
DEALLOCATE myCursor;
---------------------------------------------------------------------------
2. 关于关联字符集
由于数据库权限方面的限制,我在一个项目中需要对两个数据库中的表进行关联查询,然后碰到了字符集不匹配的报错。
具体的情况是这样的: 数据库DB1采用了GB字符集,数据库DB2采用了LATIN字符集,两个库的表T1和T2通过step_id进行JOIN,而step_id的数据类型是NVARCHAR,因此JOIN失败。
这是因为对于字符串类对象,虽然表示同样的值,当采用不同的字符集时,其存储时的值是不同的。
这个CASE给我的启示是,任何可能用于JOIN或外部引用的对象,要尽可能采用整型数据类型。
事实上,对于数据库来说,整型和日期型数据的检索速度是最快的,当有JOIN、分组查询、外部引用时,要尽可能使用整型数据。
订阅:
博文 (Atom)