搜索
bottom↓
回复: 19

求一个C语言的算法,最近脑袋不够用了。

[复制链接]

出0入0汤圆

发表于 2013-11-22 14:36:42 | 显示全部楼层 |阅读模式
本帖最后由 hck2llj 于 2013-11-22 16:17 编辑

如题,大概是这样的:
1、定义一个目标值           unsigned long target_value;
2、还有一个逐次逼近的值  unsigned long current_value;
===============================================
我希望的效果是,
当目标值target_value确定以后,
逐次逼近的值current_value从最大值FFFF_FFFFH以3ms的时间间隔逐次逼近target_value(即current_value的值3ms改变一次)。
一开始current_value的变化可以大点,但是随着它的值越来越靠近target_value,它的变化也越来越小。
而且current_value的值最终会与target_value相等。

多谢大家的关注,诚心求指导。

10楼更新了我找到的一个工程师写的代码,但是不同的编译环境执行的结果大相径庭啊,大家帮忙出个主意吧

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2013-11-22 14:37:29 | 显示全部楼层
应该发布在莫元悬赏区的,真不好意思,刚才没注意看。

出0入0汤圆

 楼主| 发表于 2013-11-22 14:42:38 | 显示全部楼层
我看到一个工程师写的是这样子的,他用得成功了,但是我移植过来,总是达不到我要的效果。
unsigned long current_value;    // 逐次逼近值
unsigned long target_value;      // 目标值

void opera()
{
       if( time_3ms_ok ) // 3ms时间到
       {
              time_3ms_ok = 0;
              current_value = current_value - (unsigned int)(*((unsigned int *)&current_value ))  * 0x300L + target_value * 0x300L ;
       }
}

出0入42汤圆

发表于 2013-11-22 14:46:16 | 显示全部楼层
这就是比例控制吧

出0入0汤圆

发表于 2013-11-22 15:17:49 | 显示全部楼层
就是PID控制里面 只用到了P 控制周期3ms
current_value =  target_value*p2 -  current_value * p1;

出0入0汤圆

 楼主| 发表于 2013-11-22 15:26:18 | 显示全部楼层
y595906642 发表于 2013-11-22 15:17
就是PID控制里面 只用到了P 控制周期3ms
current_value =  target_value*p2 -  current_value * p1; ...

是很像,但是又不完全是。我看到的应用是这个样子的:
unsigned long a;//当前值
unsigned long b;//目标值
a = a - (unsigned int)(*(( unsigned int *)&a))*0x300L + b *0x300L;

这个句子每3ms执行一次,一通计算下来,a总能无限逼近b。
你所说的p1,这个值一直在变化。这个难道是模糊PID?

出0入0汤圆

发表于 2013-11-22 15:30:28 | 显示全部楼层
current_value = current_value  + (target_value - current_value)* 0x300L ;
去掉强制转换。就是一个p调节。
各种强制转换是为了防止运算的时候溢出。

出0入0汤圆

 楼主| 发表于 2013-11-22 15:33:10 | 显示全部楼层
关于以后 发表于 2013-11-22 15:30
current_value = current_value  + (target_value - current_value)* 0x300L ;
去掉强制转换。就是一个p ...

仔细想了一下,看来有动力去重新看一下PID了,写谢过大家

出0入0汤圆

发表于 2013-11-22 15:38:50 | 显示全部楼层
本帖最后由 lcw_swust 于 2013-11-24 11:55 编辑

给楼主一个温控例子:
(注意这里面全是有符号数)
void pid(void)
{
static S16 err1,err2;
S16 err0,add;
err0=Ts-Tr;//设定值减实际值
add=Pid_p*(err0-err1)+Pid_i*err0+Pid_d*((err0-err1)-(err1-err2));//计算输出的增量
Iout=Iout+add;//改变加热器的输出电流
err2=err1;
err1=err0;//保存本次误差
}
当Pid_p=Pid_d=0,Pid_i=0x300L,与楼主的程序有相似之处,但是楼主的程序中缺了输出量

出0入0汤圆

 楼主| 发表于 2013-11-22 16:10:17 | 显示全部楼层
谢谢大家的建议,我会好好去思考的。
补上一个消息,刚才我在不同的编译环境下尝试了以下代码,结果让我很惊讶。
==================================================
unsigned long LVelocity ;
unsigned int Capcs = 23603 ;
unsigned long Capcs32 = 0xFFFFFFFF ;

int main( void )
{
    while(1)
    {
         if (Capcs > 500)
        {
            Capcs32 = Capcs32 - (unsigned int)(*((unsigned int *)&Capcs32)) * 0x200L + Capcs * 0x200L;
        }
        if (*((unsigned int *)&Capcs32) >= 0xFFFF)
        {
            LVelocity = 0x00;
        }
        else  
        {
            LVelocity = (unsigned long)(0xB40397 / *((unsigned int *)&Capcs32));
        }
    }
}
===============================================
LVelocity 为我想要的速度结果。
Capcs 为脉冲采样值。
Capcs32 为逐次逼近采样值的中间变量。
在飞思卡尔的CodeWarrior和keil中,我得到了想要的结果,多次计算后,LVelocity 结果为499.
但是在瑞萨的CubeSuite+和IAR FOR AVR中,LVelocity 的结果一直在不断地变化,毫无规律。

出0入0汤圆

 楼主| 发表于 2013-11-22 16:12:19 | 显示全部楼层
大家如果有时间又很感兴趣的话,可以去尝试一下。
带我的工程师说可能是因为设置的堆栈空间不够,具体他也没时间分析。
我比较小白,求指导。

出0入0汤圆

发表于 2013-11-22 16:38:13 | 显示全部楼层
PID 可以啊,不过和系数有关。

出0入0汤圆

发表于 2013-11-22 16:43:13 | 显示全部楼层
二分搜索吧。。。。。。。。。

出0入0汤圆

发表于 2013-11-24 10:42:32 | 显示全部楼层
本帖最后由 yklstudent 于 2013-11-24 10:46 编辑

修改原因 搞错了

出0入0汤圆

发表于 2013-11-24 13:21:14 | 显示全部楼层
每次变化误差值的一半就OK了

出0入0汤圆

 楼主| 发表于 2013-12-2 17:00:05 | 显示全部楼层
各位朋友,我已经找到我之前所提的这个算法的症结所在了。代码贴在下方
症结就是:
这个语句, *((unsigned int *)&Capcs32) 。如Capcs32=0x1234abcd;那么
在keil和CodeWarrior中,    这条语句的运算结果是取Capcs32的高十六位来做运算,执行该语句的结果是:0x1234
而在CubeSuite+和IAR中,这条语句的运算结果是取Capcs32的低十六位来做运算,执行该语句的结果是:0xabcd
这就导致了不一样的运算结果。
==================================================
unsigned long LVelocity ;
unsigned int Capcs = 23603 ;
unsigned long Capcs32 = 0xFFFFFFFF ;

int main( void )
{
    while(1)
    {
         if (Capcs > 500)
        {
            Capcs32 = Capcs32 - (unsigned int)(*((unsigned int *)&Capcs32)) * 0x200L + Capcs * 0x200L;
        }
        if (*((unsigned int *)&Capcs32) >= 0xFFFF)
        {
            LVelocity = 0x00;
        }
        else  
        {
            LVelocity = (unsigned long)(0xB40397 / *((unsigned int *)&Capcs32));
        }
    }
}
===============================================

出0入0汤圆

发表于 2013-12-2 17:18:38 | 显示全部楼层
大小端?

出0入0汤圆

 楼主| 发表于 2013-12-2 17:27:16 | 显示全部楼层

这个我也不知道了,我找到了造成问题的原因,但找不到这个原因的解释,

出0入0汤圆

发表于 2013-12-2 17:33:09 | 显示全部楼层
嗯  你出现的这个问题是关于编译器大小端的,你最好google之。呵呵

出0入0汤圆

 楼主| 发表于 2013-12-2 17:37:55 | 显示全部楼层
AnSir007 发表于 2013-12-2 17:33
嗯  你出现的这个问题是关于编译器大小端的,你最好google之。呵呵

我看了一下下,是这个问题,存储高低字节的位置造成的,现在看看有没有解决的方法
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 14:14

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表