l*******c 发帖数: 523 | 1 如果有个t的函数:
V(t) = sqrt { (Va)^2 + [(Vb)^2 - (Va)^2]*[1-e^(kt/20)]/(1-e^T)};
Va是已知的值;
Vb也是已知的值;
k, T是常数。
然后k从1到20,有没有简单的算法可以减少for循环里运算量?以下是那段code:
if (Vb > Va)
deltaDAC = (Vb * Vb - Va * Va)/(1-exp(T));
else
deltaDAC = (Va * Va - Vb * Vb)/(1-exp(T));
if (Vb > Va)
{
for (k=1; k <= 20; k++)
{
Data1 = Va * Va;
Data2 = deltaDAC * (1-exp(k/20));
DAC_Set_Value = sqrt(Data1 + Data2);
DAC_Output(DAC_Set_Value, Dir);
Delay_us(DelayTime);
} |
X****r 发帖数: 3557 | 2 1.只看见循环,没看见递归。
2.你确定瓶颈在这个式子?每个循环你的delay就要不少时间吧?
【在 l*******c 的大作中提到】 : 如果有个t的函数: : V(t) = sqrt { (Va)^2 + [(Vb)^2 - (Va)^2]*[1-e^(kt/20)]/(1-e^T)}; : Va是已知的值; : Vb也是已知的值; : k, T是常数。 : 然后k从1到20,有没有简单的算法可以减少for循环里运算量?以下是那段code: : if (Vb > Va) : deltaDAC = (Vb * Vb - Va * Va)/(1-exp(T)); : else : deltaDAC = (Va * Va - Vb * Vb)/(1-exp(T));
|
l*******c 发帖数: 523 | 3 sorry,因为是DAC的关系,所以应该没有递归。Vb和Va分别是已知calibration table
里的值,look-up table就可以找到了。
你说的没错,那些delay time是由CPU的时间所决定的,这些瓶颈我没办法改。
我只是想知道,对于指数函数开平方的运算,有没有什么简单的算法,可以加快运算速度。 |
N***m 发帖数: 4460 | 4 你确定程序的瓶颈在指数开平方?
table
速度。
【在 l*******c 的大作中提到】 : sorry,因为是DAC的关系,所以应该没有递归。Vb和Va分别是已知calibration table : 里的值,look-up table就可以找到了。 : 你说的没错,那些delay time是由CPU的时间所决定的,这些瓶颈我没办法改。 : 我只是想知道,对于指数函数开平方的运算,有没有什么简单的算法,可以加快运算速度。
|
y***d 发帖数: 2330 | 5 if either kt or T is const, you can save the exp of them.
【在 X****r 的大作中提到】 : 1.只看见循环,没看见递归。 : 2.你确定瓶颈在这个式子?每个循环你的delay就要不少时间吧?
|
b***i 发帖数: 3043 | 6 你难道不能提前算好,甚至利用编译器算好?
table
速度。
【在 l*******c 的大作中提到】 : sorry,因为是DAC的关系,所以应该没有递归。Vb和Va分别是已知calibration table : 里的值,look-up table就可以找到了。 : 你说的没错,那些delay time是由CPU的时间所决定的,这些瓶颈我没办法改。 : 我只是想知道,对于指数函数开平方的运算,有没有什么简单的算法,可以加快运算速度。
|
l*******c 发帖数: 523 | 7 k是变量,从1到20。
【在 y***d 的大作中提到】 : if either kt or T is const, you can save the exp of them.
|
l*******c 发帖数: 523 | 8 本来是算好了,时间都满足spec.
可是现在客户改了标准,需要更快的时间内完成。不想改硬件,从新做板子了,看算法
上有没有什么可以提高的。
【在 b***i 的大作中提到】 : 你难道不能提前算好,甚至利用编译器算好? : : table : 速度。
|
y***d 发帖数: 2330 | 9 save an array of 20
【在 l*******c 的大作中提到】 : k是变量,从1到20。
|
V********n 发帖数: 3061 | 10 我觉得公式的计算部分消耗的时间微乎其微,
倒是你这个output和delay很有可能是拖后腿的。
如果不需要每计算一次就output和delay的话,
那么把下面这两句尽量移到循环体外做:
DAC_Output(DAC_Set_Value, Dir);
Delay_us(DelayTime);
尤其是那个output,到底是去做了什么操作了?
不能先把结果放到一个数组里,全部算完了再输出吗? |
|
|
l*******c 发帖数: 523 | 11 那个output和delay有特别的用途。为了抵消step response function 产生的ringing.
【在 V********n 的大作中提到】 : 我觉得公式的计算部分消耗的时间微乎其微, : 倒是你这个output和delay很有可能是拖后腿的。 : 如果不需要每计算一次就output和delay的话, : 那么把下面这两句尽量移到循环体外做: : DAC_Output(DAC_Set_Value, Dir); : Delay_us(DelayTime); : 尤其是那个output,到底是去做了什么操作了? : 不能先把结果放到一个数组里,全部算完了再输出吗?
|
V********n 发帖数: 3061 | 12 那你把下面三步合为一步,可以减少两次生成中间变量并寻址的动作,对减少时间有帮
助:
Data1 = Va * Va;
Data2 = deltaDAC * (1-exp(k/20));
DAC_Set_Value = sqrt(Data1 + Data2);
改成:
DAC_Set_Value = sqrt(Va * Va + deltaDAC * (1-exp(k/20)));
说实在的,现在的编程上很少会需要去考虑这么细微的区别。如果你真的对时间抠到纳
秒的地步,这么做也许会有点帮助。
ringing.
【在 l*******c 的大作中提到】 : 那个output和delay有特别的用途。为了抵消step response function 产生的ringing.
|
b***i 发帖数: 3043 | 13 你的公式里有t,可是代码却没有t是怎么回事?
【在 l*******c 的大作中提到】 : 如果有个t的函数: : V(t) = sqrt { (Va)^2 + [(Vb)^2 - (Va)^2]*[1-e^(kt/20)]/(1-e^T)}; : Va是已知的值; : Vb也是已知的值; : k, T是常数。 : 然后k从1到20,有没有简单的算法可以减少for循环里运算量?以下是那段code: : if (Vb > Va) : deltaDAC = (Vb * Vb - Va * Va)/(1-exp(T)); : else : deltaDAC = (Va * Va - Vb * Vb)/(1-exp(T));
|
b***i 发帖数: 3043 | 14 提前算好,就是利用编译器把运算结果放进数组,这样当然不用重新做板子,只是一个
代码的改变而以。象你这种就20个不同浮点数,放到数组里就是最好的方法。
【在 l*******c 的大作中提到】 : 本来是算好了,时间都满足spec. : 可是现在客户改了标准,需要更快的时间内完成。不想改硬件,从新做板子了,看算法 : 上有没有什么可以提高的。
|
l*******c 发帖数: 523 | 15 恩,这个应该可以省一点时间。
【在 V********n 的大作中提到】 : 那你把下面三步合为一步,可以减少两次生成中间变量并寻址的动作,对减少时间有帮 : 助: : Data1 = Va * Va; : Data2 = deltaDAC * (1-exp(k/20)); : DAC_Set_Value = sqrt(Data1 + Data2); : 改成: : DAC_Set_Value = sqrt(Va * Va + deltaDAC * (1-exp(k/20))); : 说实在的,现在的编程上很少会需要去考虑这么细微的区别。如果你真的对时间抠到纳 : 秒的地步,这么做也许会有点帮助。 :
|
l*******c 发帖数: 523 | 16 是这样的,客人随时可能给一个命令去任意一个channel (或者说voltage),而我这里为
了消除每次step response function 带来的震荡,每次从当前的voltage去到客户要求
的voltage,我都必须分20步走完。
打个比方说,从channel 1 到 channel 88, 客户可以从channel X 到任意一个channel
Y.这里面的组合太多了。所以说,我没法把每个情况都用array做,因为CPU internal
的flash memory是有限的。
【在 b***i 的大作中提到】 : 提前算好,就是利用编译器把运算结果放进数组,这样当然不用重新做板子,只是一个 : 代码的改变而以。象你这种就20个不同浮点数,放到数组里就是最好的方法。
|
c******e 发帖数: 545 | 17 Delay_us就空耗CPU时间?完全可以做点别的啊。也就是说,你在等DAC settle的这段
时间里,至少可以完成下个数值的一部分运算了 |
b***i 发帖数: 3043 | 18 把Data1的计算放循环外面,把1-e^kt这20个数放到数组里面提前算好,在循环中直接取数,少个指数运算。然后是否可以根据运算所花费的时间调整下一次等待时间?
另外你确信cache打开了?
【在 l*******c 的大作中提到】 : 如果有个t的函数: : V(t) = sqrt { (Va)^2 + [(Vb)^2 - (Va)^2]*[1-e^(kt/20)]/(1-e^T)}; : Va是已知的值; : Vb也是已知的值; : k, T是常数。 : 然后k从1到20,有没有简单的算法可以减少for循环里运算量?以下是那段code: : if (Vb > Va) : deltaDAC = (Vb * Vb - Va * Va)/(1-exp(T)); : else : deltaDAC = (Va * Va - Vb * Vb)/(1-exp(T));
|
d*1 发帖数: 24 | 19 这段code为什么要用if else? 不直接用绝对值? |
N***m 发帖数: 4460 | 20 这个不会节省什么时间,而且Va Vb未必是大于0。
不过十有八九是正的。
【在 d*1 的大作中提到】 : 这段code为什么要用if else? 不直接用绝对值?
|
|
|
t****t 发帖数: 6806 | 21 他这个显然是firmware, 跟一般的软件不同, 就是需要比较精确的时间和速度控制
【在 V********n 的大作中提到】 : 那你把下面三步合为一步,可以减少两次生成中间变量并寻址的动作,对减少时间有帮 : 助: : Data1 = Va * Va; : Data2 = deltaDAC * (1-exp(k/20)); : DAC_Set_Value = sqrt(Data1 + Data2); : 改成: : DAC_Set_Value = sqrt(Va * Va + deltaDAC * (1-exp(k/20))); : 说实在的,现在的编程上很少会需要去考虑这么细微的区别。如果你真的对时间抠到纳 : 秒的地步,这么做也许会有点帮助。 :
|
N***m 发帖数: 4460 | 22 你说得准没错
【在 t****t 的大作中提到】 : 他这个显然是firmware, 跟一般的软件不同, 就是需要比较精确的时间和速度控制
|
t****t 发帖数: 6806 | 23 我理解你每一步输出需要延时, 但是你说的"需要更快时间内完成"是指减短这个延时的
时间吗?
如果不是, 那是指什么时间呢?
如果是, 那你可以缩短Delay_us(DelayTime)吗?
ringing.
【在 l*******c 的大作中提到】 : 那个output和delay有特别的用途。为了抵消step response function 产生的ringing.
|
b***i 发帖数: 3043 | 24 假设他原来准备计算需要10微秒,每次输出之后等待20微秒。
他说客户改变了要求,结果每次计算需要40微秒,结果不等待都无法在规定时间内完成
任务了,所以需要优化。
解决方案很简单,把所有可以提前算好的算好,不要在循环里面计算。还有,单片机的
设置要正确,很多人cache没有打开,结果把时钟改快10倍都不够。很多情况,编译器
有问题,表达式的一种写法可以比另一种快10倍以上。多试试就好了。说必定他已经改
好了,所以不来了。
【在 t****t 的大作中提到】 : 我理解你每一步输出需要延时, 但是你说的"需要更快时间内完成"是指减短这个延时的 : 时间吗? : 如果不是, 那是指什么时间呢? : 如果是, 那你可以缩短Delay_us(DelayTime)吗? : : ringing.
|
l*******c 发帖数: 523 | 25 “需要更快时间内完成” 并不是指的减短这个输出需要的延时,这个输出需要的延时
是精心计算和对每个器件都测试的,目的是为了消除震荡的ringing。这个延时跟器件
本身的震荡周期有直接关系。
我这里指的“需要更快时间内完成”是指器件对客户的响应。
比如说,客户需要2ms内器件就要有正确的反应。这个时间包含了器件recieve command
, check look-up table, 所有运算和计算,以及送出command.
【在 t****t 的大作中提到】 : 我理解你每一步输出需要延时, 但是你说的"需要更快时间内完成"是指减短这个延时的 : 时间吗? : 如果不是, 那是指什么时间呢? : 如果是, 那你可以缩短Delay_us(DelayTime)吗? : : ringing.
|
l*******c 发帖数: 523 | 26 我还没弄好呢。今天忙娃忙了一天。
明天回去公司查查看cache。 现在用的是atmel的MCU.时钟是40MHz。
【在 b***i 的大作中提到】 : 假设他原来准备计算需要10微秒,每次输出之后等待20微秒。 : 他说客户改变了要求,结果每次计算需要40微秒,结果不等待都无法在规定时间内完成 : 任务了,所以需要优化。 : 解决方案很简单,把所有可以提前算好的算好,不要在循环里面计算。还有,单片机的 : 设置要正确,很多人cache没有打开,结果把时钟改快10倍都不够。很多情况,编译器 : 有问题,表达式的一种写法可以比另一种快10倍以上。多试试就好了。说必定他已经改 : 好了,所以不来了。
|
t****t 发帖数: 6806 | 27 所以你需要减少的是循环前面那段的时间不是么? 而不是循环内的计算.
换句话说, 你需要减少的是这段程序开始到第一个DAC_output的时间对吧. 我理解你每
两个DAC_output之间的时间是不能变的, 即Delay_us()的时间+循环内的计算时间是个
常量.
这是我一开始的预计, 但是你问的是减少"这个循环里的运算量", 所有人都被你误导了.
command
【在 l*******c 的大作中提到】 : “需要更快时间内完成” 并不是指的减短这个输出需要的延时,这个输出需要的延时 : 是精心计算和对每个器件都测试的,目的是为了消除震荡的ringing。这个延时跟器件 : 本身的震荡周期有直接关系。 : 我这里指的“需要更快时间内完成”是指器件对客户的响应。 : 比如说,客户需要2ms内器件就要有正确的反应。这个时间包含了器件recieve command : , check look-up table, 所有运算和计算,以及送出command.
|
l*******c 发帖数: 523 | 28 是这样的,如果说器件的震荡周期是T,那倘若我能在这1个T内走越多的步数越好(现在
是20步),当步数趋于无穷是,所有的ringing将被抵消。但由于CPU的限制,1个T内所
走的步数是有限的,而如果步数不够多的话,器件产生的ringing是没法消得很干净的
。所以我现在用的是3个T的时间。换句话说,我用震荡周期的整数倍的时间来换取走的
步数变多。
如果我能减少循环体内的时间,delay_us()的时间是可以减少的(例如从3个减少到1个
T)。
当然循环体外的时间能减少也是对客户的响应时间有帮助的。
了.
【在 t****t 的大作中提到】 : 所以你需要减少的是循环前面那段的时间不是么? 而不是循环内的计算. : 换句话说, 你需要减少的是这段程序开始到第一个DAC_output的时间对吧. 我理解你每 : 两个DAC_output之间的时间是不能变的, 即Delay_us()的时间+循环内的计算时间是个 : 常量. : 这是我一开始的预计, 但是你问的是减少"这个循环里的运算量", 所有人都被你误导了. : : command
|
l*******c 发帖数: 523 | 29 在这里面,器件的震荡周期是1ms.而客户需要的响应时间是4ms. 所以这里面delay_us(
)是贡献了最多的时间消耗。可惜受CPU的limit限制,倘若在当前的CPU情况下,能改善指数开平方的运算量,在1个T内增加几倍的步数,也就是k从1到20变成1到几十而这部分的时间不变,那delayus()是可以减少2ms,那就可以满足客户的要求了。
了.
【在 t****t 的大作中提到】 : 所以你需要减少的是循环前面那段的时间不是么? 而不是循环内的计算. : 换句话说, 你需要减少的是这段程序开始到第一个DAC_output的时间对吧. 我理解你每 : 两个DAC_output之间的时间是不能变的, 即Delay_us()的时间+循环内的计算时间是个 : 常量. : 这是我一开始的预计, 但是你问的是减少"这个循环里的运算量", 所有人都被你误导了. : : command
|
t****t 发帖数: 6806 | 30 你怎么前后矛盾, 那就是说你最终的目的还是减少每一步输出的延时, 以增加循环的次
数? 那你刚才怎么说不是减短这个延时?
us(
善指数开平方的运算量,在1个T内增加几倍的步数,也就是k从1到20变成1到几十而这
部分的时间不变,那delayus()是可以减少2ms,那就可以满足客户的要求了。
【在 l*******c 的大作中提到】 : 在这里面,器件的震荡周期是1ms.而客户需要的响应时间是4ms. 所以这里面delay_us( : )是贡献了最多的时间消耗。可惜受CPU的limit限制,倘若在当前的CPU情况下,能改善指数开平方的运算量,在1个T内增加几倍的步数,也就是k从1到20变成1到几十而这部分的时间不变,那delayus()是可以减少2ms,那就可以满足客户的要求了。 : : 了.
|
|
|
l*******c 发帖数: 523 | 31 你总结的是对的。我开始想错了,总想着在不改变delay_us()的时候,尽量加快运算速
度。
【在 t****t 的大作中提到】 : 你怎么前后矛盾, 那就是说你最终的目的还是减少每一步输出的延时, 以增加循环的次 : 数? 那你刚才怎么说不是减短这个延时? : : us( : 善指数开平方的运算量,在1个T内增加几倍的步数,也就是k从1到20变成1到几十而这 : 部分的时间不变,那delayus()是可以减少2ms,那就可以满足客户的要求了。
|
t****t 发帖数: 6806 | 32 除了减少delay_us之外, 能做的就是common subexpression elimination了, 如果编译
器比较原始的话可能需要自己做, 所以你做的式子是
dac_set_value = sqrt(va*va + deltadac*(1-exp(k/20))) (有没有exp(k/20*T)?)
= sqrt(va*va + deltadac - deltadac*exp(k/20))
= sqrt(G - deltadac*exp(k/20))
其中G=va*va + deltadac, 另外如果内存够的话, exp(k/20)也可以查表, 一般内存会
比exp快一些. 也可以考虑一些近似的算法计算exp. 前提是你的20或者whatever步数是
个常数.
【在 l*******c 的大作中提到】 : 你总结的是对的。我开始想错了,总想着在不改变delay_us()的时候,尽量加快运算速 : 度。
|
t****t 发帖数: 6806 | 33 在本版混的都知道, 问问题的往往问的不是他们的本意. 最好不要替他们解释:)
【在 b***i 的大作中提到】 : 假设他原来准备计算需要10微秒,每次输出之后等待20微秒。 : 他说客户改变了要求,结果每次计算需要40微秒,结果不等待都无法在规定时间内完成 : 任务了,所以需要优化。 : 解决方案很简单,把所有可以提前算好的算好,不要在循环里面计算。还有,单片机的 : 设置要正确,很多人cache没有打开,结果把时钟改快10倍都不够。很多情况,编译器 : 有问题,表达式的一种写法可以比另一种快10倍以上。多试试就好了。说必定他已经改 : 好了,所以不来了。
|
l*******c 发帖数: 523 | 34 大牛,谢了。明天我把code改了再测测时间。
【在 t****t 的大作中提到】 : 除了减少delay_us之外, 能做的就是common subexpression elimination了, 如果编译 : 器比较原始的话可能需要自己做, 所以你做的式子是 : dac_set_value = sqrt(va*va + deltadac*(1-exp(k/20))) (有没有exp(k/20*T)?) : = sqrt(va*va + deltadac - deltadac*exp(k/20)) : = sqrt(G - deltadac*exp(k/20)) : 其中G=va*va + deltadac, 另外如果内存够的话, exp(k/20)也可以查表, 一般内存会 : 比exp快一些. 也可以考虑一些近似的算法计算exp. 前提是你的20或者whatever步数是 : 个常数.
|
b***i 发帖数: 3043 | 35 一样的,如果1-exp(k/20)放表里面,乘法,加法,开方
G的计算反正是循环外面的。
还是楼主自己自己才能说清楚,每次等待的时间改了就行了
【在 t****t 的大作中提到】 : 除了减少delay_us之外, 能做的就是common subexpression elimination了, 如果编译 : 器比较原始的话可能需要自己做, 所以你做的式子是 : dac_set_value = sqrt(va*va + deltadac*(1-exp(k/20))) (有没有exp(k/20*T)?) : = sqrt(va*va + deltadac - deltadac*exp(k/20)) : = sqrt(G - deltadac*exp(k/20)) : 其中G=va*va + deltadac, 另外如果内存够的话, exp(k/20)也可以查表, 一般内存会 : 比exp快一些. 也可以考虑一些近似的算法计算exp. 前提是你的20或者whatever步数是 : 个常数.
|
a****l 发帖数: 8211 | 36 比如说,如果现在的电压是0V,目标是跳到10V,你现在就让输出20步,每步上升0.5V,这样
的做法和你的做法会有什么样的不同?
【在 l*******c 的大作中提到】 : 如果有个t的函数: : V(t) = sqrt { (Va)^2 + [(Vb)^2 - (Va)^2]*[1-e^(kt/20)]/(1-e^T)}; : Va是已知的值; : Vb也是已知的值; : k, T是常数。 : 然后k从1到20,有没有简单的算法可以减少for循环里运算量?以下是那段code: : if (Vb > Va) : deltaDAC = (Vb * Vb - Va * Va)/(1-exp(T)); : else : deltaDAC = (Va * Va - Vb * Vb)/(1-exp(T));
|
t****t 发帖数: 6806 | 37 我觉得线性变化的电压, 从频谱上来看通常不是件好事.
【在 a****l 的大作中提到】 : 比如说,如果现在的电压是0V,目标是跳到10V,你现在就让输出20步,每步上升0.5V,这样 : 的做法和你的做法会有什么样的不同?
|