多年来本人在研发团队里担任算法设计工程师,设计过的算法包括:电能计量、复杂控制、无线通信和系统架构等。蓦然回首,顿悟算法设计有很多共性,抽取出来大致为6个步骤,结合近段时间设计的一个算法撰写了这个方法论。主要用于总结经验,提高自身的生产力;如果不小心启发了他人,也算是对业界的一点小贡献。
例:在一个无线通信系统中,节点定时上报数据给网关(如下图红色时隙),同时也支持网关唤醒节点(如下图绿色时隙),为此需要设计“唤醒算法”。要求:
1. WakeTime被网络内所有节点和网关共享;
2. WakeTime必须避开主动上报,否则将“冲突出错”且“耗能增大”;
3. 它比较适合于“第N个WakeUp”计算“第(N+1)个WakeTime”;
4. 它必须尽可能得简单;
在该算法中存在如下参数:
1. reserved slot:保留时隙,即在此段时隙中没有节点主动上报;
2. slot idle:空闲时隙,即相邻两个节点之间隔离的时间;
3. wake exchange:唤醒通信时间,即网关唤醒节点并与其进行交互通信时长;
前面2个参数的解释如下图所示:
上面3个参数组合成如下4种应用场景:
令x=第x次wake,f(x)=第x次wake time,则有:
f(x)=N*wakeperiod+nofly+(x-1)*wakeinterval (1)
safeguard=(wakeperiod-nofly)%wakeinterval (2)
已知:当前RTC值,求隔离最近的wake time值如下:
第一步:if(RTC / wakeperiod != (RTC + safeguard) / wakeperiod)
RTC += safeguard;
第二步:计算N值:N = RTC / wakeperiod;
第三步:计算x的值:
x = (RTC + wake interval –N * wake period –nofly) / wakeinterval;
if (x < 0) x= 0;
x += 1;
第四步:将N和x代入公式(1)计算出f(x)值。
第五步:检查wake time是否与UPLINK相冲突:
wake end = wake time + wake exchange –1;
if (wake time / wake period != wake end/ wake period)
wake time = wake end / wake period* wake period + nofly;
实例一:
实例条件:
wake period |
nofly |
wake interval |
wake exchange |
safeguard |
65 |
40 |
10 |
5 |
5 |
计算数据如下表:
RTC |
+safeguard |
N |
x |
f(x) |
wake end |
wake time |
0~39 |
/ |
0 |
1 |
40 |
44 |
40 |
40~49 |
/ |
0 |
2 |
50 |
54 |
50 |
50~59 |
/ |
0 |
3 |
60 |
64 |
60 |
60~64 |
65~69 |
1 |
1 |
105 |
109 |
105 |
65~104 |
/ |
1 |
1 |
105 |
109 |
105 |
实例二:
实例条件:
wake period |
nofly |
wake interval |
wake exchange |
safeguard |
63 |
40 |
10 |
5 |
3 |
计算数据如下表:
RTC |
+safeguard |
N |
x |
f(x) |
wake end |
wake time |
0~39 |
/ |
0 |
1 |
40 |
44 |
40 |
40~49 |
/ |
0 |
2 |
50 |
54 |
50 |
50~59 |
/ |
0 |
3 |
60 |
64 |
103 |
60~62 |
63~65 |
1 |
1 |
103 |
107 |
103 |
63~102 |
/ |
1 |
1 |
103 |
107 |
103 |
一般来说需要编码实现该算法,覆盖应用场景组织测试数据,让系统自动遍历测试数据,检验算法的正确性。白盒测试有助于:跟踪系统的运行,遍历程序分支,还可以优化软件;黑盒测试有助于:快速查看结果,检查算法输出是否正确。往往实验会找出算法缺陷,此时根据反馈需要重新设计或修正。
本实例算法代码清单如下:
static int32_t CalcWakeTime(int32_t lRTC)
{
int32_t lRTCVal, lXInterval,lMulDiv, lWakeTime, lWakeEnd;
lRTCVal = lRTC;
/* Check whether need to add safeguard. */
if ( lRTCVal / s_stSlotWakeTime.lUplinkPeriod !=
(lRTCVal +s_stWakeParam.nSafeGuard) / s_stSlotWakeTime.lUplinkPeriod )
{
lRTCVal += s_stWakeParam.nSafeGuard;
}
/* Calculate value of "N" */
ASSERT(0 < s_stSlotWakeTime.lUplinkPeriod);
lMulDiv =lRTCVal / s_stSlotWakeTime.lUplinkPeriod;
/* Calculate value of "x" */
lXInterval = (lRTCVal + s_stWakeParam.lWakeInterval) - lMulDiv *s_stSlotWakeTime.lUplinkPeriod -
s_stWakeParam.lNoFly;
lXInterval /= s_stWakeParam.lWakeInterval;
if (lXInterval < 0)
{
lXInterval = 0;
}
++lXInterval;
/* wake time = N * wake period + nofly + (x - 1) * wake interval. */
lWakeTime = lMulDiv * s_stSlotWakeTime.lUplinkPeriod +s_stWakeParam.lNoFly + (lXInterval - 1) *
s_stWakeParam.lWakeInterval;
ASSERT(lRTC< lWakeTime);
/* Check collision between WAKE and UPLINK. */
lWakeEnd = lWakeTime + s_stSlotWakeTime.nWakeExchange - 1;
if (lWakeTime / s_stSlotWakeTime.lUplinkPeriod != lWakeEnd /s_stSlotWakeTime.lUplinkPeriod)
{
lWakeTime = lWakeEnd / s_stSlotWakeTime.lUplinkPeriod *s_stSlotWakeTime.lUplinkPeriod +
s_stWakeParam.lNoFly;
}
returnlWakeTime;
}