2009年4月27日星期一
还是minicom好用
用下来的感受是windows下可以做的事情Ubuntu下完全可以做到,加上我们是在用嵌入式linux进行开发,所以完全应该在Ubuntu下进行,忘掉Windows吧~
回到主题,说说minicom。前面写过一篇文章,里面说minicom用不惯,用了它的一个前端——cutecom。这几天使用下来,发现cutecom的一个重要缺点——显示时乱码。这个问题其实不是它所独有的,在Windows下的DNW和一般的串口调试助手都会出现这个问题。在Windows下的解决方法是使用自带的超级终端,它不仅不会显示乱码,还可以彩色显示,带tab自动补全,甚至可以利用zmodem协议来传输小文件!
那么Ubuntu下有没有这样的好东西呢?当然有了,那就是minicom!minicom的使用其实很简单,先用"minicom -s"启动设置界面,将串口名,波特率,握手协议等设定好,保存为默认的df1,以后只要用"minicom -m -c on"打开就可以了,不用再进行串口设置。直接使用minicom和超级终端一样自带tab补全,也可以利用zmodem协议传输文件,只要在输入rc后按Alt+S,就会出现选择要传输文件的提示窗口,在其中用空格选择要传输的文件,最后按回车就可以开始传输了。传输过程中有进度提示,完毕后会自动回到minicom的命令行。唯一让我不爽的是对中文支持不好,不过暂时用的都是英文,按理说minicom应该也能支持中文的,好像是-8选项,但我还没倒腾出来,就先不说了,以后再来研究~
2009年4月24日星期五
在嵌入式开发中使用Qt
gunzip qt-x11-opensource-src-4.3.2.tar.gz
tar xvf qt-x11-opensource-src-4.3.2.tar
./configure -qvfb
make
make install
2. 交叉编译嵌入式Qtopia-core。这里的configure参数对于最终库文件的大小和支持的功能至关重要,一定要确保加入了足够的功能,同时不需要的功能一个也不要!
gunzip qtopia-core-opensource-src-4.3.2.tar.gz
tar xvf qtopia-core-opensource-src-4.3.2.tar
cd /tmp/qtopia-core-opensource-src-4.3.2
在qtopia-core-opensource-src-4.2.2/src/gui/embedded/qmouselinuxtp_qws.h加入
#define QT_QWS_IPAQ
#define QT_QWS_IPAQ_RAW
以上两个定义是为了支持触摸屏
在下面的configure参数中,-prefix指定了最后install的目录,
./configure -prefix /home/ace/Qtopiacore-4.3.2 -no-largefile -xplatform qws/linux-arm-g++ -no-libtiff -no-gif -no-libmng -no-openssl -no-cups -no-qdbus -embedded arm -little-endian -no-freetype -qt-gfx-linuxfb -no-qt3support -depths 8,16
make
make install
将编译好Qtopiacore-4.3.2下lib库放到根文件系统的Qtopiacore下 (注意根文件系统中的目录要和-prefix /home/ace/Qtopiacore-4.3.2一样否则下到arm板上运行程序的时候会报错说找不到字体)。
如果报错说找不到libstc++.so.6文件,可以将usr/local/arm/3.4.1/arm-linux/lib/libstc++.so.6复制到/home/ace/Qtopiacore-4.3.2/lib下(或者软链接)。
为了实现触摸屏的校准将/home/ace/Qtopiacore-4.3.2/examples/qtopiacore/mousecalibration/mousecalibration拷贝到根文件系统中,在文件系统的.bashrc文件中加入环境变量,并且export QWS_MOUSE_PROTO="LinuxTP:/dev/h3600_tsraw"。
3. 制作根文件系统及进行触摸屏校准。
将根文件系统下到arm板子上去,启动板子运行./mousecalibration -qws 进行触摸屏的校准。
校准完后 cat /etc/pointercal,将显示的数据记录下来, 然后新建一个空白文档将其命名为pointercal ,然后将记录的数据放到pointercal文档中。
rm -f /etc/pointercal
sudo cp -f 新建的pointercal /etc
sudo chown 500:244 /etc/pointercal
制作根文件系统,烧到arm板子。
4. Done!
2009年4月15日星期三
基于svm的驾驶决策建模
对于整个驾驶过程决策建模,要考虑在不同的驾驶阶段,驾驶者关注的决策变量是不同的。如果对各种不同的驾驶阶段分别进行基于svm的建模,当然可以,但需要另外对不同阶段间的转换进行判断,而各个阶段之间的过渡往往是模糊的,不同阶段转换的会很复杂,工作量甚至可能超过svm建模!为避免这个问题,我们用一个包含所有阶段的决策变量的状态空间来进行建模。以基本的跟驰阶段为例,用四个决策变量就可以进行驾驶决策了,但这时要给出所有决策变量在该时刻的值,如果没有的话就设为某一固定值(一般取为0即可),这样驾驶者在不同驾驶阶段的转换逻辑也包含在了状态空间模型中,不用另外做判断的工作,只需在每一时刻给出所有决策变量的值,大大简化了驾驶决策的建模。
本方法的优点很明显,但是缺点和前文类似,都需要包含各种类型决策变量的数据来进行训练,数据质量的好坏直接影响了模型的有效性和完备性。虚拟驾驶数据采集系统是解决这一问题的最佳方案!
知道如何在blogger里发帖子了
现在是在Ubuntu下,刚才偶尔打开一个blogger上自己以前写的帖子,发现速度还可以,就尝试着进入控制台发个帖子,发现速度还不错!以后就在Ubuntu下发blogger的帖子了~但是在本地写的东西放在CintaNote里,在xp系统下,拷贝到Ubuntu下不是很方便,要想个办法~
2009年3月23日星期一
2009年3月19日星期四
[转]利用消息队列实现进程间通信
所谓消息功能,是指由一个进程产生并送出的消息,被放在一个叫做“消息队列”的列中管理,然后由接收方从消息队列中取出消息,这么一种功能。(先入先出)
做一个例子程序看看:
下面的两个程序分为发送方和接收方。发送方将自己的PID和从标准输入输入的一个字符串送至消息队列,接收方把消息队列中所有的PID和字符串读出,并输出至标准输出。
/* msend.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
int main()
{
int msqid;
key_t msgkey;
struct msgbuf
{
long mtype;
char mdata[256];
};
struct msgbuf msgdata , *p ;
p = &msgdata ;
printf('Enter message : ');
fflush( stdin ); /* 刷新标准输入缓冲区 */
gets( p->mdata ); /* 输入字符串 */
p->mtype = getpid();
msgkey = ftok ( 'mrecv' , 'a' ); /* 计算标识符 */
msqid = msgget( msgkey , IPC_CREAT | 0666 ) ; /* 建立消息队列 */
msgsnd( msqid , p , sizeof(p->mdata) , 0 ); /* 送消息 */
return 0;
}
/* mrecv.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
int main()
{
int msqid;
key_t msgkey;
struct msgbuf
{
long mtype;
char mdata[256];
};
struct msgbuf msgdata , *p ;
p = &msgdata ;
msgkey = ftok( 'mrecv' , 'a' ); /* 计算标识符 */
msqid = msgget( msgkey , IPC_CREAT | 0666 ) ; /* 取得消息队列的ID */
while(1)
{
msgrcv( msqid , p , sizeof(p->mdata) , 0 , 0 ) ; /* 读消息 */
printf('Message received from %ld\n%s\n' , p->mtype , p->mdata );
}
return 0;
}
执行例:
% msend
Enter message : Hello , world
%msend
Enter message : I am Syuu I
%mrecv
Message received from 321
Hello , world
Message received from 326
I am Syuu I
使用消息功能,可分如下几步
发送方:
1.生成消息队列,取得ID。
2.向消息队列送消息。
接收方:
1.根据标识符,取得ID。
2.从消息队列接收消息。
3.删除消息队列。
例程序相对来说比较简单。我们就不解释了。
消息队列的使用方法以及函数的构造等等基本上和上一章所讲的共享内存的使用方法一样。可参考上一章来理解本章内容。
说说出现的函数:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget( key_t msgkey , int flag );
取得一个消息队列的ID,如不存在则建立。
返回值: 成功时:消息队列的ID
失败时:-1
int msgsnd( int msqid , struct msgbuf *msgp , size_t msgsiz , int msgflag );
向消息队列送消息
返回值: 成功时:0
失败时:-1
msqid是消息队列的ID,size_t msgsiz是结构体成员mdata的大小,msgflag与上一章所讲的共享内存的flag起一样的作用,不过,当这个参数为IPC_NOWAIT的时候,如果消息队列已满,则返回错误值。如果不为IPC_NOWAIT,在消息队列已满 的情况下,会一直等到消息队列有空地方的时候再发送。
注意这里的这个 struct msgbuf *msgp 。要求的格式如下:
struct msgbuf
{
long mtype;
char mdata[256];
};
long mtype在这里我们用来保存本进程的PID。mdata则是保存要发送的数据。由于mdata的大小不一定(根据实际需要定义),所以这个结构体并没有事先定义好。但是我们定义这个结构体的时候一定要遵循这个规定。你可以改的,只有mdata的大小,和结构体的名称。尽量不要修改结构体成员的名称和类型。实际上,根据mtype,我们还可以有所选择地接受消息。这在下面将会谈到。
int msgrcv( int msqid , struct msgbuf *msgp , size_t msgsiz , long msgtyp , int msgflag );
从消息队列取得一个消息
返回值: 成功时:0
失败时:-1
msqid , *msgp , msgsiz不用说了。long msgtyp是结构体msgbuf的mtype成员。msgflag与上述一样。只不过为IPC_NOWAIT的时候,如果消息队列是空的,则等到有消息可读的时候再读。当不为IPC_NOWAIT的时候,如果消息队列是空的,则返回错误值(与字面上理解的有些相反)
同样地,为了控制管理消息队列,一样有一个函数msgctl()如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl( int msqid , int cmd , struct msqid_ds *buf );
返回值: 成功时:0
失败时:-1
cmd所指定的值与共享内存部分相同。
本来还应该有一章关于Semaphore的。其使用方法于共享内存和消息队列差不多,只不过使用场合不同。可是我自己也没太弄明白那个东东是怎么回事,为了避免以讹传讹……就不写了。
看了我这么多贴子,大家辛苦了。《UNIX系统程序设计》这一系列的贴子到此宣告完成。在这些文章的创作过程中得到了SOHU C\C++论坛诸位朋友的大力支持。在此笔者深表谢意。
接下来,如果有时间的话,我会继续写一套《UNIX网络程序设计(C语言版)》。不知大家有兴趣否。
再有一点。本文中所解释的所有的函数,严格地说,应该叫:系统调用( system call )。"
[转]利用共享内存实现进程间通信
在两个进程间共享数据的方法,至今为止我们只说过利用管道。管道只是利用了输入输出重定向的原理,非常简单。而且只能在父子进程间使用。很多场合下这种方法是无法满足我们的要求的。
那么现在,我们又有了一种新的方法——利用共享内存(shared memory)。这可以使我们在任意两个进程间传递数据,而且也是相对简单容易实现的一个方法。
注意:在正常情况下,一个进程的所使用的内存区是不允许其它进程访问的。这里我们要开辟的共享内存是例外。
我们来做一个简单的剪贴板。从标准输入向mcut输入数据,mcut将其放在共享内存中,然后mpaste从共享内存中读出数据并显示。
/* mcut.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main()
{
key_t shmkey;
int shmid , in_tmp ;
char *head , *pos ,
in_data[4096] , *in_ptr ;
shmkey = ftok( 'mcut' , 'a' ); // 计算标识符
// shmid开辟共享内存
shmid = shmget( shmkey , sizeof(in_data) , IPC_CREAT | 0666 ) ;
head = pos = shmat( shmid , 0 , 0 ); // 允许本进程使用这块共享内存
in_ptr = in_data ;
// 开始从标准输入输入数据,暂时存在in_data里。
while( (in_tmp=getchar()) != EOF )
{
*in_ptr = in_tmp ;
in_ptr++ ;
}
*in_ptr = '\0' ;
in_ptr = in_data ;
// 开始写入共享内存
while( *in_ptr != '\0' )
{
*pos = *in_ptr ;
pos++;
in_ptr++;
}
*pos = '\0' ;
shmdt( head ); // 禁止本进程使用这块内存
return 0;
}
/* mpaste.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int main()
{
key_t shmkey;
int shmid;
char *head , *pos ,
out_data[4096] , *out_ptr ;
shmkey = ftok( 'mcut' , 'a' ); // 计算标识符
// 开辟共享内存
shmid = shmget( shmkey , sizeof(out_data) , IPC_ALLOC | 0666 );
head = pos = shmat( shmid , 0 , 0 ); // 允许本进程使用这块共享内存
out_ptr = out_data ;
// 从共享内存中取得数据
while( *pos != '\0' )
{
*out_ptr = *pos ;
out_ptr++ ;
pos++ ;
}
*out_ptr = '\0' ;
printf( '%s\n' , out_data );
fflush( stdout );
shmdt( head ); // 禁止本进程使用这块共享内存
return 0;
}
如何?明白多少了?
要使用共享内存,应该有如下步骤:
1.开辟一块共享内存 shmget()
2.允许本进程使用共某块共享内存 shmat()
3.写入/读出
4.禁止本进程使用这块共享内存 shmdt()
5.删除这块共享内存 shmctl()或者命令行下ipcrm
上面的程序中用到了如下函数,我们一一解释一下。
首先是ftok()。它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。ftok()会返回一个key_t型的值,也就是计算出来的标识符的值。
其次,操作共享内存,我们用到了下面的函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget( key_t shmkey , int shmsiz , int flag );
void *shmat( int shmid , char *shmaddr , int shmflag );
int shmdt( char *shmaddr );
shmget()是用来开辟/指向一块共享内存的函数。参数定义如下:
key_t shmkey 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。但是刚才我们的两个进程没有任何关系,所以就用ftok()算出来一个标识符使用了。
int shmsiz 是这块内存的大小.
int flag 是这块内存的模式(mode)以及权限标识(关于权限的意思,请参阅本系列第五章)。
模式可取如下值: 新建:IPC_CREAT
使用已开辟的内存:IPC_ALLOC
如果标识符以存在,则返回错误值:IPC_EXCL
然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。
如: IPC_CREAT | IPC_EXCL | 0666
这个函数成功时返回共享内存的ID,失败时返回-1。
shmat()是用来允许本进程访问一块共享内存的函数。
int shmid是那块共享内存的ID。
char *shmaddr是共享内存的起始地址
int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
成功时,这个函数返回共享内存的起始地址。失败时返回-1。
shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。
参数char *shmaddr是那块共享内存的起始地址。
成功时返回0。失败时返回-1。
此外,还有一个用来控制共享内存的shmctl()函数如下:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl( int shmid , int cmd , struct shmid_ds *buf );
int shmid是共享内存的ID。
int cmd是控制命令,可取值如下:
IPC_STAT 得到共享内存的状态
IPC_SET 改变共享内存的状态
IPC_RMID 删除共享内存
struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。
返回值: 成功:0
失败:-1
刚才我们的mpaste.c程序中还可以加入这样几句。
struct shmid_ds buf;
... ...
shmctl( shmid , IPC_STAT , &buf ); // 取得共享内存的状态
... ...
shmctl( shmid , IPC_RMID , &buf ); // 删除共享内存
注意!!!!!!!!!:在使用共享内存,结束程序退出后。如果你没在程序中用shmctl()删除共享内存的话,一定要在命令行下用ipcrm命令删除这块共享内存。你要是不管的话,它就一直在那儿放着了。
简单解释一下ipcs命令和ipcrm命令。
取得ipc信息:
ipcs [-m|-q|-s]
-m 输出有关共享内存(shared memory)的信息
-q 输出有关信息队列(message queue)的信息
-s 输出有关“遮断器”(semaphore)的信息
%ipcs -m
删除ipc
ipcrm -m|-q|-s shm_id
%ipcrm -m 105"
[转]UNIX进程(Process)及信号(signal)
在进程执行过程中,如果出现什么事件(event),系统将会给进程一个信号。进程可以在得到这个信号后做些适当的处理。
还是与以前一样,咱们先来个小程序吧。
/* slot.c */
#include <stdio.h>
#include <signal.h>
int x[3];
long kin;
int kekka();
int main( int argc , char *argv[] )
{
srand( getpid() ); /* 设定随机数的种子数 */
signal( SIGKILL , kekka ); /* 当Ctrl+C按下时,执行kekka函数 */
kin = atoi( argv[1] ); /* 取得赌注数目 */
printf('press Ctrl+C to stop maching !\n');
while(1)
{
x[0]=rand()%10;
x[1]=rand()%10;
x[2]=rand()%10;
printf('%d %d %d\n',x[0],x[1],x[2]);
fflush( stdout );
}
return 0;
}
int kekka()
{
if( x[0]==x[1] && x[1]==x[2] )
printf('Great , you won %d \n' , kin*3000);
else
printf('You lost %d\n',kin);
exit(0); /* 游戏结束。退出程序 */
}
执行方法:
%./slot 100
执行后。画面上会出现一排排的数字。当你按下Ctrl+C的时候,程序得到信号,跳转至kekka()函数入,判断随机数。然后退出程序。
这里有这样一个新函数。是我们在UNIX程序设计中时常用得到的。
#include <signal.h>
int ( *signal( int sig , void (*func()) ))();
返回值: 成功时:进程中断地址
错误时:SIG_ERR
这个函数挺不好懂呵。解释解释。它的意思是,当收到SIG这个信号时,跳转至func()这个函数处继续执行。
int sig这个参数其实好办。下面我们会给出一个表。将其所有的参数一并列出。这是在头文件中#define的,代表各种不同的信号。
void ( * func() )
这个参数是一个函数指针。意思是在SIG信号被传给进程后,所要执行的部分。
此外,func()这个参数还可以为如下值:
SIG_DEL 系统的默认动作
SIG_IGN 忽略这个信号。
signal作用只有一次,当一个信号发生,触发signal动作的之后,signal就不起作用了。比方说,在上例中,如果你把所有的exit(0)全去掉(不退出程序),程序会进入无限循环中。你按一次Ctrl+C,signal执行一次,显示出结果。然后继续循环,生成随机数,输出。你再按Ctrl+C,signal就不好使了。
如果需要重复使用signal()函数,可以考虑在signal调用的动作函数中再加一个signal,比方说在上例的程序中再加一个 signal( SIGKILL , kekka );
加了signal这个函数后,整个程序如果没收到信号,则正常执行。否则跳转至signal中指定的func()函数处继续。
当然,我们不可能,也没有必要去为每一个信号指定一个动作。当未指定动作的信号发生的时候,系统会执行默认的动作。比方说我们知道:当Ctrl+C按下的时候,正常默认的动作是结束程序。但是,Ctrl+C按下时,发生的信号是SIGKILL,如果你为SIGKILL这个信号指定了一个动作的话,系统将去执行你指定的这个动作,而不管原来默认的了。
打个比方让大家更容易懂一些:
比方说:你在睡午觉。突然来了一个美女(帅哥)(Ctrl+C)让你陪她/他去逛街购物共进晚餐……(此处删去若干字),你正常的默认的动作是马上起来陪她出去玩(程序中止)。但是你妈说不许去,你妈说你得在家擦窗户,你只好留在家擦窗户(signal()指定的动作)。擦完窗户之后你可以选择陪美女去逛街(默认动作,Ctrl+C的埸合是退出程序,即上例程序中的exit(0)),可以选择继续睡觉(回到原来中断的地方继续执行,上例程序中如果没有exit(0),便会回到中断处继续执行)。
(大哥。打个比方嘛。干嘛拿臭鸡蛋砸我……)
signal种类非常多,在此不一一列出。
使用这个函数,你可以防止用户按下Ctrl+C结束程序。还可以做很多其它的事——只有你想不到的,没有C做不到的。
注意:根据UNIX系统的不同,signal的定义是不一样的。比方说,有的老式UNIX工作站上SIGINT是按下del键后发生的信号,而有些机型上刚是按下Ctrl+Z发生的。在使用时要注意。"
[转]标准输入输出以及管道操作
标准输入输出大概所有的操作系统都差不多吧。从键盘输入。从屏幕输出。除非你用的还是打纸带的老家伙。呵呵。
主要说一下管道操作。注意:此处所说的管道操作不是
% cat -n test.c | more
这是在提示符状态下使用管道,把第一个程序(cat)的输出作为输入传给第二个程序(more)。我们现在要在程序中使用的管道原理与此相同。将某一个程序的输出变为另一个程序的输入。
做一个石头剪子布的程序。其中包括一个父程序和一个子程序。注意是两个程序,不是两个函数。也不是两个进程。不过因为父程序运行的时候要通过exec()函数来执行子程序。所以我们也可以把它看成是两个进程。
父进程取得用户的输入(石头S,剪子C,布P中的某一个,P=0,S=1,C=2)并通过管道传给子进程
子进程取得父进程传来的数字,加上自己的PID后做为种子数,生成一个随机数然后被3除,得出来一个余数是0、1或者2。再通过管道传回给父进程。
父进程根据两个数字(用户输入的,以及子进程传回来的)判定胜负,输出
/* parent. */
#include <sys/types.h>
#include <stdio.h>
int main()
{
int i , j ,
st , fd[2] ;
pid_t pid ;
static int result[3][3]={1,0,2,2,1,0,0,1,2};
char argv1[3] , argv2[3] ,
ch ;
ch=getchar();
switch(ch)
{
case 'P': i=0;break;
case 'S': i=1;break;
case 'C': i=2;break;
default:
fprintf( stderr , 'Enter P , S or C , Please!\n' );
exit(1);
}
if( pipe(fd)!=0 ) //建立管道
{
fprintf( stderr , 'PIPE Error !\n' );
exit(1);
}
sprintf( argv1 , '%d' , fd[0] );
sprintf( argv1 , '%d' , fd[1] );
switch( pid=fork() ) // fork出一个新的进程,执行子程序
{
case 0:
if( execl('child','child',argv1,argv2,(char *)0) == (-1)) exit(1);
//执行了子程序
break;
case -1:
fprintf( stderr , 'fork Error !\n' );
exit(1)
}
write( fd[1], &i , sizeof(i) ); //向管道写数据
wait( &st ); //等待子程序结束
read( fd[0] , &j , sizeof(j) ); //从管道读数据
switch(result[j])
{
case 0:
printf( 'You won\n' );
break;
case 1:
printf( 'Same\n' );
break;
case 2:
printf( 'You lost\n' );
}
close(fd[0]);
close(fd[1]);
return 0;
}
/* child.c */
#include <stdio.h>
int main(int argc , char *argv[])
{
int i,j,
read_fd,
write_fd;
read_fd=atoi( argv[1] ); //设定输入用管道
write_fd=atoi( argv[2] ); //设定输出用管道
read( read_fd , &i , sizeof(i) ); //从管道中取得数据
srand( i+getpid() ); //设定随机数的种子数
j=rand()%3; //生成随机数
write( write_fd , &j , sizeof(j) ); //写向管道
close( read_fd );
close( write_fd );
return 0;
}
编译执行父程序即可。
这种管道是用来在父子进程间传递数据的。如同大家在程序中所见:父进程开辟管道,然后生成子进程执行子程序,并将管道参数作为main()函数的参数传给子程序。通过一个相同的管道实现读写。开辟管道时,我们用到了这个函数:
int pipe( int fd[2] ); 开辟一个管道
参数fd[2]是一个有两个元素的数组。可以看成是两个管道的记述子。fd[0]用来读,fd[1]用来写。
返回值: 成功时:0
失败时:-1
读取/写入管道时,我们用到了下面函数
读取管道中的数据
int read( int fd , char *buf , unsigned int nbyte );
向管道中写入数据
int write( int fd , char *buf , unsigned int nbyte );
其中,fd是管道记述子,也就是我们前面说的fd[0]或者fd[1],buf装数据,nbyte指定读/写数据的数量,单位是字节。成功时返回0,失败时返回-1。
由于准备考研。这篇文章耽误了一些时日。最近还有些事,也许下一篇也得几天后才能再贴。
另外,在此向诸位致歉。我的程序是在学校的UNIX下写的,一般是用软盘带回来,写上一篇贴子程序的时候没有带软盘,只好打印出来回来再敲。在输入的时候有一个错误(现已改正)
int main( int argc , char *argvp]);
应为
int main( int argc , char *argv[]);
下一章准备说说UNIX的进程(Process)和信号(signal)。"
[转]目录及文件操作
上一章我们说了一些UNIX的文件系统的物理构造。下面我们来看看具体怎么对文件进行操作。当然这里所说的文件及目录操作不是fopen()。呵呵。我们要做一些fopen办不到的事。
/* newer.c 比较参数所指定的两个文件
将其中新的文件的文件名输出来 */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
int main( int argc , char *argvp] )
{
struct stat buf[2] , *p ;
if( argc!=3 )
{
fprintf( stderr , 'Usage : %s file1 file2\n' , argv[0] );
exit(1);
}
p=buf;
if( stat(argv[1],p)!=0 ) //取得第一个文件的信息
{
fprintf( stderr , '%s not found !\n' , argv[1] );
exit(1);
}
p++;
if( stat(argv[2],p)!=0 ) //取得第二个文件的信息
{
fprintf( stderr , '%s not found !\n' , argv[2] );
exit(1);
}
if( buf[0].st_mtime > buf[1].st_mtime ) //比较最终更新时间
printf( '%s\n' , argv[1] );
else
printf( '%s\n' , argv[2] );
return 0;
}
执行结果:
%newer afile bfile
bfile
使用stat()函数,可以得到文件的信息。这些信息是在i node中保存的这个文件信息的一部分。得到的信息将会保存在stat.h中定义的stat型的结构体中。stat()函数解释如下:
#include <sys/types.h>
#include <sys/stat.h>
int stat( char *path , struct stat *buf );
返回值: 成功时:0
失败时:-1
我们再来写一个玩玩
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#define MASK 0555 //这个数字的意思等一下解释,他代表“可读”和“可执行”
int main( int argc , char *argv[] )
{
struct stat buf[1];
mode_t mode;
if( argc!=2 )
{
fprintf( stderr , 'Usage : %s file\n' , argv[0] );
exit(1);
}
if( stat(argv[1],buf)!=0 )
{
fprintf( stderr , 'Cannot read i-node\n' );
exit(1);
}
mode = ( buf[0].st_mode & MASK ); //计算文件新的权限标志
if ( chmod(argv[1],mode)!=0 ) //改变文件的权限标志
{
fprintf( stderr , 'Cannot change mode\n' );
exit(1);
}
return 0;
}
现在来解释一下0555这个数字的意思。
众所周知,UNIX是一个多用户多任务的操作系统。每个用户有自己的权限,这个权限限制了用户可以做哪些事,不可以做哪些事。对于文件来说,用户可以分成四类:
root(根用户,超级用户)
这个用户是系统的管理呐,权限最大,可以随意读写任何文件。
owner(文件拥有者)
实际拥有文件的用户。文件属主。
group(组成员)
用户所在的用户组的成员
other
以上三类之外的其它用户
UNIX中,每个文件信息中包括一组9位的权限标志。分别给文件属主,用户组和其他用户指定对该文件的读、写和执行权。请看下面的例子:
%ls -l /bin/ls
-rwxr-xr-x 1 root bin 27281 Aug 15 2002 /bin/ls*
重要是看-rwxr-xr-x,第一个 - 表示这是一个普通文件,这个位置也可以出现些别的字符,比方说目录的话这里会是 d 。而 l 表示一个链接。余下的9位可以分成三段,每段三位。本例中从左至右
rwx 表示文件的属主拥有文件的读,写,执行权
r-x 表示同组的用户拥有文件的读,执行权(注意 ,“写”权限的位置是一个 - )
r-x 表示其它的用户拥有文件的读,执行权
文件的访问权限还可以用三位8进制来表示。如上例
rwx r-x r-x 可以换成
111 101 101 (有该权限,则该位为1,否则为0)
换成8进制, 二进制的111是八进制的7 , 二进制的101是八进制的5。
现在看看0555是什么意思?就是说,可以读,可以写的意思。
把0555和原来文件的权限标志做与运算,得到的新的权限标志就是把原来的文件权限标志中所有的写权限全取消了。其余权限变。然后在程序中用chmod()把这个新的权限标志赋给文件即可。
chomd()函数用法如下:
#include <sys/types.h>
#include <sys/stat.h>
int chmod( char *path , mode_t mode );
返回值: 成功时:0
失败时:-1
关于目录,还有另一个比较有用的函数,即chdir()。用这个函数可以在程序中转换当前目录。
#include <sys/types.h>
#include <sys/stat.h>
int chdir( char *path );
返回值: 成功时:0
失败时:-1
以上两章,简单地叙述了一下UNIX的文件系统以及在UNIX C中对文件的操作方法。并列举了常用的一些函数。
下一章,我们将简单地叙述一下UNIX C的输入输出,以及用管道(pipe)实现两个进程互换数据。"
[转]在程序中执行UNIX命令或者其它程序
在UNIX下,像DOS的command.com那样的程序,我们称之为外壳(shell)。外壳就是一个命令解释器,你在外壳的提示符下输入命令(如同DOS的提示符一样),系统便会执行。
DOS的提示符一般是C:>,当然,你想改成什么样就能改成什么样,又当然,像BBS一样贴张图上去是不太现实的。
UNIX的提示符根据外壳的不同是不同的。
为了更好地说明本章想讲解的内容,我们先做一个外壳试试(玩具级别的)。我们给他起名叫SSH(Sohu Shell)吧。想取名叫CSH,可惜CSH在没生我之前就有了。呵呵。
/* 简单的外壳程序 */
#include<stdio.h>
int main()
{
static char prompt[64]='> ';
char command[256];
int st;
fprintf(stderr,'%s',prompt); // 在屏幕上输出提示符
while(gets(command)!=NULL) // 取得命令
{
if(fork()==0) // 生成子进程
{ // 这里是子进程接下来要做的事
if( execl(command,command,(char *)0)==(-1) )
// 上一句是执行命令
exit(1); // 当出错时子进程异常中止
}
else
{ // 父进程
wait(&st); // 等待子进程结束
fprintf(stderr,'%s',prompt);
// 输出提示符,等待命令
}
}
return 0;
}
执行方法:
%./ssh
>/bin/ls
当前目录下文件名一览
>Ctrl+D
%
普通的外壳在执行exit命令后会关闭。也就是说,退出一层外壳。咱们这个程序现在还做不到。愿意的话加上这个功能试试好了。所以要关闭这个外壳就得来点狠的。Ctrl+D,Ctrl+C什么的。再不你就再开一个外壳然后ps -ef再kill。再狠一些……拆硬盘,拨电源
我们这里有了一个新的函数:execl()。其实他是一组函数中的一个。这组函数如下:
int execl( path , arg0 , arg1 , ... , argn , (char *)0 );
int execv( path , argv );
int execle( path , arg0 , arg1 , ... , argn , (char *)0 , envp );
int execve( path , argv , envp );
int execlp( file , arg0 , arg1 , ... , argn , (char *)0 );
int execvp( file , argv );
其中的参数定义如下:
char *path;
char *file;
char *arg0 , *arg1 , ... , *argn;
char *argv[];
char *envp[];
返回值: 成功时:所执行的命令将会覆盖现有的进程,所以无返回值
失败时:-1
用过TC的朋友应该知道,TC的Process.h里有一个system()函数。这组函数其实和system()的功能差不多。
比方说:
execl( '/bin/ls' , '/bin/ls' , '-al' , '/home' , (char *)0 );
或者
char *argv[];
strcpy( argv[0] , '/bin/ls' );
strcpy( argv[1] , '-al' );
strcop( argv[2] , '/home' );
execv( '/bin/ls' , argv );
都相当于在命令行下敲入了'/bin/ls -al /home'并且回车。(引号不是命令里的。是我解释时加上去的。别看混了)。
execle()和execve(),函数名最后一个字母都是e。就是说,这两个函数在调用其它程序的同时,还可以把环境变量一起传给被调程序
execlp()和execvp(),函数名最后一个字母都是p,就是说,这两个函数在使用的时候,就算你不指定命令文件所在的路径,它也会根据环境变量PATH去挨个地方找。找着就执行。找不着拉倒。
比方说:
setenv $path = ( /bin $path ) 这句话将环境变量PATH的第一个路径设为/bin。这是在SHELL下执行的。C里没这东西吧。
在程序中这样用这个函数
execlp( 'ls' , 'ls' , '-al' , '/home' , (char *)0 );
与上面的效果一样。当然。如果你PATH变量没设好的话。它就不一定找到哪儿去了。
还有一个函数是wait(),说明如下:
#include <sys/types.h>
pid_t wait(int *stat_loc);
返回值就是一个PID了。忘了PID是什么意思的朋友光顾一下我上一篇贴子。
它的参数有些意思。其实它与你的子进程用什么方式结束有关系。当你的子进程以exit()方式结束的话,stat_loc所指向的地址的前8位将会是exit()的参数的后8位,而stat_loc所指向的地址的后8位是0。比方说:你的子进程是exit(1);那stat_loc所指向的地址的内容应该是0000 0001 0000 0000。
exit():
#include <stdlib.h>
void exit(int status);
就算你在程序中没写exit()函数,编译器也是认为你是在最后加入了这个函数。"
[转]生成一个Process(进程)
进程是什么?简单地说,进程就是在执行状态下的一个程序(包括CPU状态,所占内存的状态,等等)
A进程生成了B进程,也就是说,A程序在执行的时候,又生成了另一个进程B。这个时候,我们可以把A进程叫做父进程,把B进程叫做子进程。
例程序:
// Usage : ./a.out 20
#include<stdio.h>
int main( int argc , char *argv[])
{
int dep_time;
dep_time = atoi( argv[1] )*60 ; //将参数中给出的20(分钟)转换成整型的秒数
if( fork()==0 ) //生成子进程,然后父进程中止
{
sleep( dep_time );
fprintf( stderr , '!!!!!!!!n');
}
return 0;
}
上面的程序是一个闹钟程序。当你执行之后。程序不会显示什么,而是一下就回到UNIX的提示符下。但是你在命令行中指定了20分钟后你有事,那么在你执行这个程序之后20分钟,他会提醒你到时间了。
本程序只是做示例用,没有检查参数是否正确,等等。
生成一个新的进程,可以使用 fork() 函数 。以下说说fork()函数。
头文件: #include <sys/types.h>
形式 pid_t fork();
参数 无
返回值 成功时: 父进程中:子进程的PID (Process ID)
子进程中:0
失败时: 父进程中:-1
由于失败,没有生成子进程;
fork()刚执行完的时候,子进程和父进程是完全一模一样的两份进程(当然,PID是不一样的)。他们的各个变量的值都是一样的,而且都认为自己已经执行完fork()了。fork()后,区分父进程和子进程,只要看fork()的返回值就行了。
if( fork()==0 ) printf('这是子进程');
else printf('这是父进程');
同理:
if( fork()==0 )
{
//接下来要子进程做的工作
}
else
{
//接下来要父进程做的工作
}
一般,我们会把fork()返回给父进程的值保存下来(其实就是子进程的PID),等到需要结束子进程的时候,我们关掉他,如下:
pid_t child_pid ;
child_pid=fork();
if( child_pid==0 )
{
// ... ...
}
else
{
// ... ...
}
// ... ...需要结束子进程的时候
kill( child_pid , SIGKILL ) // kill()函数是用来发给另一个进程一个消息的。以后再讲。"
[转]向其它进程传递信号
第八章:向其它进程传递信号
上一章,我们简单地说了一下信号。信号不仅仅可以在本进程内使用,还可以向其它的进程传递。确切地说,一般情况下,一个进程收到的信号绝大部分是从系统的INIT传来的。而INIT也是一个进程。
用过UNIX或者LINUX的朋友大概都知道,UNIX系的操作系统里,有一个kill命令。如果你的一个进程无法中止,可以使用kill命令强行干掉它。
%kill mypro
我们自己也可以做个简单的kill命令。
/* nkill.c */
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
int main( int argc , char *argv[] )
{
pid_t pid;
if( argc != 2 ) // 检查命令行参数个数
{
fprintf( stderr , Usage : %s PID \n , argv[0] );
exit(1);
}
pid = atol( argv[1] );
if( kill( pid , SIGKILL )!=0 ) // 向pid这个进程传送一个SIGKILL信号
{
fprintf( stderr , kill failed\n );
}
return 0;
}
执行例:
%sleep 300 & (后台睡眠300秒)
[1] 520
%nkill 520
[1] + Killed sleep 300
你用自己写的程序杀死了一个sleep进程。没事。杀了就杀了吧。留着也是垃圾……
说明一下,众所周知,UNIX是非常注意用户的权限的。所以,如果你向你自己生成的进程发送SIGKILL的话,这个进程会中止。如果你是向别的(你没有写权限的)进程发送SIGKILL的话,除非那个进程允许你动它,否则你发了也是白发。打个不恰当的比较下流一些的比方:如果你要求亲一下你自己老婆的话(你有“亲”的权限),你会如愿以偿。但是如果你想亲一下别人的老婆的话(你没有“亲”的权限),除非他及她同意,否则……呵呵。你死定了。
所以,执行上面的程序的时候,你必须保证你有权限关掉那个进程。可不是说你ps -ef然后随便挑一个进程就能关的。要不那黑客也太好当了。
几乎是咱们的老规矩了:先写个程序,然后解释这个程序,说说其中新出现的函数。这回还照旧吧。
大家看到了。这里新出来一个kill()函数。解释如下:
#include <sys/types.h>
#include <signal.h>
int kill( pid_t pid , int sig );
返回值: 成功时:0
失败时:-1
这个函数是向进程ID(PID)为pid的进程传送一个sig信号。
这个函数有什么用呢?用处可大了。
在上一章中,我们用到了SIGKILL信号。这一节我们用的还是这个信号。实际上,信号(signal)有许多。而且根据UNIX系统的不同,这些信号也不太一样。
我们简单列举一些信号例子。其用途请恕小生才疏,解释不清。有兴趣的朋友可以自己查阅一下资料。
SIGHUP , SIGINT , SIGQUIT , SIGILL , SIGTRAP , SIGABRT , SIGEMT , SEGFPE(注意,这里是SEG),SIGKILL , SIGBUS , SIGSEGV , SIGSYS , SIGPIPE , SIGALRM , SIGTERM , SIGUSR1 , SIGUSR2 , SIGCLD , SIGPWR , SIGWINCH , SIGSTOP , SIGTSTP , SIGCONT , SIGTTIN , SIGTTOU
使用kill()函数,可以将这些信号中的一个或者多个送至另一个进程。刚才的程序中,我们就是将一个SIGKILL信号送至sleep那个进程,该进程收到信号,以为是用户按下了Ctrl+C,就中止了。
知道了这些, 我们再来做一个比较有意思的程序。我们做一个cat程序(类似于DOS下的type,查看文本文件的内容)。不过这个cat程序与UNIX的cat不太一样,我们把由参数指定的文件的内容输出到屏幕上。如果你没指定文件,那么这个程序会等你五秒,在这五秒钟里,你可以从标准输入输入一个文件。然后显示。万一这五秒钟里你也没输入什么文件名。程序会把当前目录下的所有文件名打印出来(ls),以督促你输入一个文件名。
/* show.c */
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
jmp_buf env;
int func();
int main( int argc , char *argv[] )
{
char filename[256];
signal( SIGALRM , func ); // 如果收到一个SIGALRM信号,则转至func处执行
if( argc==1 )
{
fprintf( stderr , & );
alarm(5); // 5秒钟后向自己发送一个SIGALRM信号
setjpm(env); // 设置记号
scanf( %s , filename );
execl( /usr/bin/more , more , filename , (char *)0 );
}
else
{
execl( /usr/bin/more , more , argv[1] , (char *)0 );
}
return 0;
}
int func()
{
int st;
fprintf( stderr , Which file do you want to read ?\n\n );
if( fork()==0 )
{
execl( /bin/ls , ls , -FCa , (char *)0 );
}
wait(&st);
longjmp( env , 0 ); // 跳转至先前的setjmp()处
}
这个程序看明白了吗?可能有些不太好懂。我们从头跑一遍试试。
首先是装入头文件等等。没关系了。然后signal( SIGALRM , func ),即,当收到一个SIGALRM信号的时候,中断现在所做的工作。转而执行func()函数。
不过可惜得很,现在暂时还没人给咱们发送SIGALRM信号,我们继续往下看。下面是判断命令行参数了。如果只有这个程序的可执行文件一个参数的话(也就是说,没有指明要显示哪个文件的内容),那就打印出一个&号来。然后设置alarm(5),也就是说,在5秒后给自己发一个SIGALRM信号。下一句setjpm(env)是设置一个记号,以后当执行至longjmp()函数的时候,就会跳转到这里来。然后等待你输入文件名。
如果在这五秒种里,你输入了一个文件名的话,那么就向下执行——通过execl()函数调用系统的more命令,显示该文件的内容。然后退出。这只需要要很少的一段时间。绝对用不上一秒(看你当前目录下有多少文件了。没人会在一个目录下装上1G吧?)。最后结束程序。alarm()在5秒后发出的信号乐意咋地咋地去吧。咱不用管了。
问题是:如果在这五秒钟里,你没有输入文件名的话,事情就变得非常微妙了。这种情况下,程序将停留在
scanf( %s , filename );
这一行。等待你输入文件名。然后五秒种的期限到了。alarm()函数向这个进程发了一个SIGALRM信号。signal()函数检测到这个信号,转向func()函数处执行。
func()函数先是输出了一个提示信息 Which file do you want to read ? 。然后fork()出一个子进程。这个子进程通过execl()函数调用/bin/ls命令,显示出当前目录下的所有文件。execl()函数生成的进程覆盖掉了子进程。显示完所有文件名后退出。父进程等待子进程结束(wait())后,执行longjmp()函数,返回到刚才的setjmp那行程序结尾处。继续执行下一步,也就是再执行一次 scanf( %s , filename )。当然,上一次的scanf()已经中止了。剩下的就简单地一路到底。明白了?
为什么要fork()出一个子进程,而不用原来的进程呢?是因为execl()函数会覆盖掉当前进程。如果直接使用execl()的话,咱们这个宝贝进程就被execl()覆盖,调用完 /bin/ls 后直接结束退出了。还怎么跳来跳去的呀。呵呵。
好。又多了三个函数:
unsigned alarm( unsigned sec );
在sec指定的秒数之后,向本进程发送一个SIGALRM信号。
返回值是以前的alarm()函数执行后所剩余的时间。
还记不记得第一章中,咱们做过的闹钟程序了?那个时候是让进程休眠一段时间,然后再报时。现在我们有了另一个法宝——alarm()。这回也别让进程浪费大好时光睡大觉去了。让它做点别的什么事吧。写写试试?
#include <setjmp.h>
int setjmp( jmp_buf env ); // 设置跳转记号env
void longjmp( jmp_buf env , int val ); // 跳转至记号env处。
jmp_buf env就是跳转记号了。那么longjmp第二个参数 int val 是干什么用的呢?当你用longjmp()函数跳转至setjmp()处的时候,setjmp()函数应该会返回一个值吧?这个值就是int val,也就是longjmp()第二个参数。
setjmp()的返回值,在第一次使用的时候是0。在由longjmp()跳转过来的时候,返回值是longjmp()的第二个参数。
但是有一个特例:像刚才程序中所写的,longjmp( env , 0 ),longjmp()第二个参数是 0 的时候,setjmp()的返回值是 1 。
有很多界面比较友好的程序中,当等待用户输入数据的时候,如果用户过了一段时间还没有输入的话,程序会输入一些提示信息,或者是可供选择的选项来供用户参考。在Windows编程中,例如VC,VB等等,大概可以用定时器 timer 或者其它的什么办法来解决(我粗通VB。VC一点都不会)。在UNIX下,上面那样便是一种解决方法。当然。编程习惯不同,解决方法也不尽相同。
信号(signal)这个东西,在UNIX编程中占很重要的地位。笔者一直想用通俗的语言来解释,可是限于笔者的语文水平,所以做到的仅此而已。总的来说,signal可以看成是一种软中断。当一个signal被发送到程序的时候,会引发程序的默认过程(比方说SIGKILL的场合是强制结束)或者程序的作者自定义的过程(用signal()函数指定)。
另外。longjmp()和setjmp()两个函数由于使用了跳转(类似于goto语句,但是longjmp()能实现函数外跳转,就是说能跳到另一个函数里去。goto办不到吧),这不符合结构化程序设计的要求,所以如果不是万不得以,不推荐使用。"
[转]Rise Vs Raise
但是rise多用于不及物动词(rise后面不加宾语),raise是及物动词(raise后面要加宾语).
还有个简单的方法,一般事物自身可以升高,上升的,常用rise,例如太阳东升,河水上涨.而raise一般是人为地让事物升高,例如举起胳膊,提高薪水等.
The sun rose at seven o'clock.
太阳七点钟升起。
The river is rising after the rain.
雨后河水涨了。
The plane was then able to rise and it cleared the mountains by 400 feet.
'这时飞机能上升了,并在距山头400英尺的高度飞越了山头。'
The steps of the palace rise in easy flights.
宫殿台阶上升的坡度不大。
Prices have risen steadily during the past decade.
过去十年间物价一直在上涨。
(物价上涨是不能人为控制的哦~)
He raised his arms above his head.
他把手臂举过头顶。
I will not raise a hand against you.
我不会做任何不利于你的事。
to raise salaries
提高工资
to raise the rent
提高租金"
2009年3月17日星期二
DOP和差分GPS
先来看看DOP(Dilution of Precision)精度衰减因子的概念。
DOP包括GDOP(Geometric DOP)几何精度衰减因子,PDOP(Position DOP)位置精度衰减因子,HDOP(Horizontal DOP)水平精度衰减因子,VDOP(Vertical DOP)垂直精度衰减因子和TDOP(Time DOP)时间精度衰减因子。各个因子的表达式如下:
GDOP=(Tx**2+Ty**2+Tz**2+Tt**2)**0.5/T;
PDOP=(Tx**2+Ty**2+Tz**2)**0.5/T;
HDOP=(Tx**2+Ty**2)**0.5/T;
VDOP=Tz/T;
TDOP=Tt/T;
其中Tx,Ty,Tz,Tt分别是x,y,z,t的方差。从表达式可以看出,影响GDOP的因素包括x,y,z,t,PDOP包含x,y,z,HDOP包含x,y,VDOP仅包含z,TDOP仅包含t。
再来看看差分GPS的类型。
根据差分GPS基准站发送的信息内容的不同分为位置差分,伪距差分,相位平滑伪距差分和载波相位差分四种。其工作原理相同,都是由基准站发送改正数,由游动站接收并对其测量结果进行改正。所不同的是发送的改正数的具体内容,最后得到的差分定位精度也不同。
位置差分:发送的修正量是解算坐标与参考站已知坐标的误差。优点是计算方法简单,适用于一切GPS接收机,包括最简单的接收机。缺点是必须严格保持参考站与用户观测同一组卫星。适用于用户与基准站间距离在1000km以内的情况。
伪距差分:发送的修正量是参考站与可见卫星的距离与含有误差的测量值的差值。优点是1)修正量是直接在WGS84坐标下计算的,无须坐标变换,因而可保证精度;2)这种方法能提供伪距修正量及其变化率,可以精确地考虑吧时间延迟的影响;3)它能提供所有卫星的修正量,用户可选用任意4颗卫星定位。随着用户到基准站距离的增加,卫星时钟误差被完全消除,对流层误差、接收机噪声不受距离变化的影响,星历误差、电离层误差和UERE(用户等效距离误差)随距离增加而变大。
广域增强:WAAS不是广播距各卫星的距离修正值,而是广播卫星星历的误差矢量和速率误差矢量,因此克服了局域增强(LAAS)只在小范围内起作用的缺点。
相位平滑的差分伪距是直接差分伪距观测量与推算量的加权平均。
载波相位差分:RTK(Real Time Kinematic)是建立在实时处理两个测点的载波相位基础上的。发送的修正量是基准站的载波观测量及站坐标信息。用户接收GPS卫星的载波相位与来自参考站的载波相位,组成相位差分观测值进行实时处理,能实时给出厘米数量级的定位结果。
在python中解析带符号24位数
来讲讲思路。首先是用struct.unpack将整个B1(PVT)数据块分为一个个的word,其他的U8、U16、U32、S32等2的整数次幂都好办,就是碰到S24时有点麻烦,没有直接对应的数据类型,要用间接的方法来解析数值。我采用的方法是用三个Byte来存储S24的从低到高的三个字节,然后分别左移高两位字节(一个左移8位,一个左移16位),再拼成一个完整的无符号整数(用或运算),用struct.pack包装成的字节流(就是一个字符串),然后判断是正数还是负数,如果是负数要将最高一个字节改为0xff。再用struc.unpack来解包,注意此时是作为带符号整数来解包的!这样就得到了S24的值。
说了这么多,看一下代码就清楚了~
def parseS24(self,c0,c1,c2):
s = struct.pack('<I',c0|c1<<8|c2<<16)
if c2>0x7f:
ss = list(s)
ss[3] = '\xff'
s = "".join(ss)
result = struct.unpack('<i',s)[0]
return result
def w10(self):
c0 = self.data[11]
c1 = self.data[12]
c2 = self.data[13]
result = self.parseS24(c0,c1,c2)
return result
完整的代码在下面~
2009年3月11日星期三
2009年3月8日星期日
2009年3月7日星期六
查找zotero中给定item所在的collection
一番挣扎之后,写出来了:“select collectionName from collections where collectionID = (select collectionItems.collectionID from collectionItems where itemID = (select itemData.itemID from itemData where valueID = (select valueID from itemDataValues where value = "?")))”。其中?处填上item的全称,在SQLite Spy或SQLite Manager中执行该语句即可(当然在任何支持sqlite3的软件中执行皆可)。
但这样只能查找到item直接所在的collection,而collection有可能还有上一层的collection,写出这样的SQL语句已经超出了我的能力范围,只有借助于python了~。
02 #coding=utf-8
03
04 import sqlite3 as sqlite
05
06 def findCollectionNames(itemName):
07 conn = sqlite.connect('zotero.sqlite')
08 c = conn.cursor()
09 param = (itemName,)
10 # 查找collectionName和parentCollectionID
11 c.execute("select collectionName, parentCollectionID from collections where collectionID = \
12 (select collectionID from collectionItems where itemID = \
13 (select itemID from itemData where valueID = \
14 (select valueID from itemDataValues where value = ?)))", param)
15 collectionNames = []
16 for row in c:
17 # print row[0].encode('gbk')
18 collectionNames.append(row[0])
19 parentCollectionID = row[1]
20 while parentCollectionID:
21 cur = conn.cursor()
22 param = (parentCollectionID,)
23 cur.execute("select collectionName, parentCollectionID from collections where collectionID = ?", param)
24 res = cur.fetchall()[0]
25 # print res[0].encode('gbk')
26 collectionNames.append(res[0])
27 parentCollectionID = res[1]
28
29 # We can also close the cursor if we are done with it
30 c.close()
31
32 # 显示出来
33 collectionNames.reverse()
34 for name in collectionNames:
35 print ("%s - " % name.encode('gbk')),
36 print ("\"%s\"" % itemName)
37
38 if __name__ == '__main__':
39 findCollectionNames(u"Panda3D - Forums")
2009年3月4日星期三
2009年3月3日星期二
2009年3月2日星期一
回顾一下车辆跟驰两大流派之争
Brackstone的文章总结了所有基于pysical的车辆跟驰模型,但有意无意的忽略了基于psycological的工作。这引起了心理学研究者的不满,Hancock,Boer,Ranney等人纷纷发文表示抗议,从不同的角度提出了质疑。最后,还是Brackstone在"What is the answer and come to that, what are the questions?"一文中做出了回应,肯定了心理学研究在驾驶行为研究中的贡献,同时指出了感知模型的一个重要难题:模型校准。在文章的最后他亮出了自己的观点:哪种模型更“真”,其实并不重要,只要它能用来完成手头的任务,那就是合适的答案。能最好的完成手头任务的工具,就是最合适的答案。
可以说Brackstone是物理学派(工程学派)的捍卫者,对于心理学模型无法校准的弱点,想来是心中很不屑的(对于当时工程学派中缺乏模型校准的趋势也是很不屑的)。这也确实是心理学派的一个软肋,虽然感知模型对于驾驶行为中的不确定性做了很好的解释,但苦于难以校准,始终无法应用到仿真等领域中。相反的,如果能提供一个和实测数据符合的模型,即使它没有考虑驾驶者实际的驾驶决策过程,对于仿真也是合适的工具。
2009年3月1日星期日
无模型车辆跟驰建模
对数据进行聚簇分类,采用的是层次聚类的思想,从底层开始向上构建,用簇内聚合度和簇间分离度来评价聚类质量。对高维,大数据量的数据集也有较好的效率。对非凸数据簇也能很好的识别。嘿嘿,当然不是我自己想出来的,是参考陈黎飞的文章。
上面的层次聚类方法属于离线计算方法,不适合在仿真运行中使用,因此需要一个能够对分类很好识别的方法。SVM方法就是这样一个满足需求的好方法,能从分类数据中找出若干“支持向量”,使得结构风险最小。
用SVM在线识别出新的数据点属于哪个分类后,还要根据该分类中训练数据给出的规律求出新的数据点对应的加速度值。这个规律如何得到呢?当然是要用数据拟合的方法,由分类中的训练数据拟合出一个函数。如何拟合呢?还是SVM!SVM除了可以用来分类外,还能用于回归,也就是拟合啦~原理和分类时的类似,找出若干“支持向量”,用来勾画出拟合的函数。
在用libsvm进行SVM的编程时,发现文档中说SVM的参数选择对于分类和拟合的效果(精度)有很大的影响。默认的搜索参数的方法是所谓的“网格”(grid)方法,也就是在参数的取值空间内隔一段取一个值,构成一张网,在取值空间内这么一过滤,就能筛出好的参数值了!说白了,这就是暴力搜索,网格越密,越能搜出好的参数值,但是所消耗的时间也就越长!SVM用于分类要搜索c和g两个参数值,用于拟合要搜索c,g和p三个参数值,因为不知道可能的参数值取值范围多大合适,我就把取值范围放宽了一点,网格取密了一点,结果拟合的参数算了好几天也没算出个结果出来!!
最后决定采用PSO(粒子群优化)算法来搜索参数值。PSO算法比较简单,收敛速度快,但容易收敛于局部最优,因此有各种的改良版本。看了国内两位作者的极值扰动的改良版本,受到了启发,又做了一些改进,就用它了!
实测数据用的还是那次跑车的数据,看看效果如何。必须要指出的是,无模型车辆跟驰建模对于数据的要求很高,要求能尽量覆盖所有的情况,没有覆盖到的情况当然无法得出对应的分类,也就无法在仿真中遇到相应情况时提供合理的反应。这也就自然的引出了下面的工作:虚拟测试及数据采集系统的研究。
2009年2月27日星期五
wps的zotero插件
2009年2月23日星期一
这两天忙了点啥
- SPADE,一个python实现的多智能体开发环境,使用XMPP/Jabber,还专门为JADE开发了一个XMPP的MTP插件,但在Windows下不好用,试了几个小时也没搞定,就没兴趣再整了……
- Kalman滤波器,看了原理,很简单,关键是人家写的好,还找到了一个用python实现的代码,里面给出了我看的那篇文章的链接,看来还蛮火的~:)
- Wireshark,一个开源的功能强悍的网络包抓取和分析工具,试用了一下,蛮好用的,这里还有一个中文的教程,以前我咋就不知道有这样的好东西呢!
- 在云端上找到一个timeEdition软件,可以记录在电脑上干了些什么,并且可以将结果导出放到Google calendar上,真是太和我的心意了~阿军听我介绍后马上又找出一个叫rescue time的时间记录软件,功能好像也蛮强大的~
2009年2月19日星期四
完成支持豆瓣的Zotero的translator
"translatorID":"fc353b26-8911-4c34-9196-f6f567c93901",
"translatorType":4,
"label":"Douban",
"creator":"Ace Strong<acestrong@gmail.com>",
"target":"^https?://www.douban.com/subject",
"minVersion":"1.0.0",
"maxVersion":"",
"priority":100,
"inRepository":true,
"lastUpdated":"2009-2-19 20:45:00"
}
function detectWeb(doc, url) {
var articleRe = /subject_search/;
var s = articleRe.exec(url);
if(s) {
return "multiple";
} else {
return "book";
}
return false;
}
function scrape(doc) {
//var namespace = doc.documentElement.namespaceURI;
//var nsResolver = namespace ? function(prefix) {
// if (prefix == "x") return namespace; else return null;
//} : null;
var nsResolver = null;
var itemType = "book";
var newItem = new Zotero.Item(itemType);
Zotero.debug(itemType);
// 附件,网页快照
newItem.attachments.push({document:doc, title:"web snapshot"});
//Zotero.debug(doc);
Zotero.debug("Title:");
// 标题,/html/body/div/h1
var titleTag = doc.evaluate('//html/body/div/h1', doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
//Zotero.debug("stage2:");
var title = Zotero.Utilities.trimInternal(titleTag.textContent);
Zotero.debug(title);
newItem.title = title;
// 其他信息,//*[@id="info"]
var info = doc.evaluate('//*[@id="info"]', doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
//Zotero.debug(info);
// 找出作者信息(包括译者)
var dataRows = info.getElementsByTagName("span");
//Zotero.debug(dataRows.length);
var dataRow;
var i = 0;
while(dataRow = dataRows[i]) {
i = i + 1;
var spanTags = dataRow.getElementsByTagName("span");
//Zotero.debug(spanTags.length);
if (spanTags.length>0){
// 作者或译者
var authorType = Zotero.Utilities.trimInternal(spanTags[0].textContent);
var name = Zotero.Utilities.trimInternal(dataRow.getElementsByTagName("a")[0].textContent);
//Zotero.debug(authorType);
//Zotero.debug(name);
if(authorType == "作者"){
newItem.creators.push(Zotero.Utilities.cleanAuthor(name, "author", true));
}else if(authorType == "译者"){
newItem.creators.push(Zotero.Utilities.cleanAuthor(name, "translator", true));
}
}
}
// 提取ISBN,页数,定价,出版社,装帧,出版年信息
var obmo = info.getElementsByTagName("div")[0];
var content = obmo.textContent;
//Zotero.debug(content);
dataRows = obmo.getElementsByTagName("span");
Zotero.debug(dataRows.length);
i = 0;
while(dataRow = dataRows[i]) {
i = i + 1;
var infoType = dataRow.textContent;
//Zotero.debug(infoType);
// 去除无用的信息
content = content.replace(infoType,"");
//Zotero.debug(content);
}
// 去除前后空格
content = content.replace(/(^\s*)|(\s*$)/g, "");
// 将中间的空格转换为","
content = content.replace(/\s+/g, ',');
// 分离信息
var infoContents = content.split(",");
//Zotero.debug("detail info:");
//for (x in infoContents){
// Zotero.debug(infoContents[x]);
//}
// ISBN
newItem.ISBN = infoContents[0];
// 页数
newItem.pages = infoContents[1];
// 出版社
newItem.publisher = infoContents[3];
// 出版年
newItem.date = infoContents[5];
newItem.complete();
}
function doWeb(doc, url) {
var namespace = doc.documentElement.namespaceURI;
var nsResolver = null;
if(detectWeb(doc, url) == "multiple") {
Zotero.debug("Enter multiple~");
// search page
var items = new Array();
// //*[@id="in_tablem"]
var tablemTag = doc.evaluate('//*[@id="in_tablem"]', doc, nsResolver, XPathResult.ANY_TYPE, null).iterateNext();
var tableTags = tablemTag.getElementsByTagName("table");
Zotero.debug(tableTags.length);
var tableTag;
Zotero.debug("begin to fetch multiple title and link");
var i = 0;
while(tableTag = tableTags[i]) {
i = i + 1;
var tds = tableTag.getElementsByTagName("td");
var title ="";
var link = "";
var as = tds[1].getElementsByTagName("a");
link = as[0].href;
title = as[0].textContent;
Zotero.debug(title);
Zotero.debug(link);
if(link) {
items[link] = Zotero.Utilities.cleanString(title);
}
}
// 让用户选择要保存哪些文献
items = Zotero.selectItems(items);
if(!items) return true;
Zotero.debug("go on processing.");
var urls = new Array();
for(var url in items) {
urls.push(url);
}
} else {
var urls = [url];
}
Zotero.debug(urls);
// 下面对每条url进行解析
Zotero.Utilities.processDocuments(urls, scrape, function() { Zotero.done(); });
Zotero.wait();
}
2009年2月18日星期三
用mingw编译boost,在Code::Block中使用
build.bat mingw然后将bjam.exe拷贝到根目录下(任何目录都可以啦),加入系统PATH中。回到boost的根目录,输入命令:
bjam --toolset=gcc "--prefix=D:\Boost" install然后就是等待了~
2009年2月16日星期一
2009年2月13日星期五
2009年2月12日星期四
相信我,你并不孤单!
> "D:\Python25\pythonw.exe" -u "F:\projects\svr\pso.py"显然,istPSO效果最好,但我还是不太满意,准备做进一步的优化!
training with function: Sphere
training with pso: bPSO
average value = 33895.368806, best value = 16366.455677
training with pso: sPSO
average value = 713.990013, best value = 5.145062
training with pso: tPSO
average value = 31565.762681, best value = 12586.708452
training with pso: stPSO
average value = 620.577996, best value = 5.207246
training with pso: istPSO
average value = 0.015338, best value = 0.004548
best pso is istPSO
training with function: Griewank
training with pso: bPSO
average value = 9.637782, best value = 4.977231
training with pso: sPSO
average value = 0.735644, best value = 0.191848
training with pso: tPSO
average value = 8.538446, best value = 4.857032
training with pso: stPSO
average value = 0.557846, best value = 0.187582
training with pso: istPSO
average value = 0.045185, best value = 0.000121
best pso is istPSO
training with function: Rosenbrock
training with pso: bPSO
average value = 9618082261.674509, best value = 2725173927.465609
training with pso: sPSO
average value = 179243235.044173, best value = 631.653198
training with pso: tPSO
average value = 8046176465.674629, best value = 1196837169.500892
training with pso: stPSO
average value = 2338.451929, best value = 612.315377
training with pso: istPSO
average value = 367129077.608837, best value = 29.142729
best pso is istPSO
training with function: Rastrigin
training with pso: bPSO
average value = 34903.229750, best value = 20759.712907
training with pso: sPSO
average value = 378.882609, best value = 186.164672
training with pso: tPSO
average value = 29756.547518, best value = 13739.131209
training with pso: stPSO
average value = 785.898331, best value = 205.353543
training with pso: istPSO
average value = 91.394043, best value = 1.290095
best pso is istPSO
再来说说今天看到的一个帖子,前面已经给了一个链接,从TopLanguage里看到的,点击进去看了,发现是个豆瓣的帖子,楼主开篇的话让我觉得“并不孤单”!笑来的话再次应验了:相信我,你并不孤单!
明天还要考试,今晚不能太迟睡了,再看会这个帖子,看看楼主是如何攻克拖延症的~晚上的批量测试程序就是在看到这个帖子后才开始做的,看到有这么多人和我有一样的痛苦,不觉中痛苦就减轻了很多,嘿嘿:)
2009年2月9日星期一
2009年2月4日星期三
[转]Python:time.clock() vs. time.time()
Python:time.clock() vs. time.time()
Posted by Ross Wan on 九月 19, 2008
有时候,我们需要知道程序或者当中的一段代码的执行速度,于是就会加入一段计时的代码,如下:
start = time.clock()
... do something
elapsed = (time.clock() - start)
又或者
start = time.time()
... do something
elapsed = (time.time() - start)
那究竟 time.clock() 跟 time.time(),谁比较精确呢?带着疑问,查了 Python 的 time 模块文档,当中 clock() 方法有这样的解释:
clock()
On
Unix, return the current processor time as a floating point number
expressed in seconds. The precision, and in fact the very definition of
the meaning of “processor time”, depends on that of the C function of
the same name, but in any case, this is the function to use for
benchmarking Python or timing algorithms.
On Windows, this
function returns wall-clock seconds elapsed since the first call to
this function, as a floating point number, based on the Win32 function
QueryPerformanceCounter(). The resolution is typically better than one
microsecond.
可见,time.clock() 返回的是处理器时间,而因为 Unix 中 jiffy 的缘故,所以精度不会太高。
总结
究竟是使用 time.clock() 精度高,还是使用 time.time() 精度更高,要视乎所在的平台来决定。总概来讲,在 Unix 系统中,建议使用 time.time(),在 Windows 系统中,建议使用 time.clock()。
这个结论也可以在 Python 的 timtit 模块中(用于简单测量程序代码执行时间的内建模块)得到论证:
if sys.platform == "win32":
# On Windows, the best timer is time.clock()
default_timer = time.clock
else:
# On most other platforms the best timer is time.time()
default_timer = time.time
使用 timeit 代替 time,这样就可以实现跨平台的精度性:
start = timeit.default_timer()
... do something
elapsed = (timeit.default_timer() - start)
2009年2月2日星期一
多维粒子群(PSO)算法
先从这个网站找到一个简单并且有点不靠谱的一维PSO的python实现。特点是简单,容易看懂,并且用pygame将优化过程保存成图片,方便以后查看。改为多维的实现,能运行后发现调用libsvm进行交叉校验每次都会打印出信息,大大减慢了算法的速度!于是昨晚就调试怎么去掉这个了~
今天早上起来想到那个保存成图片的功能不错,多维算法可以指定其中一维来实现,大不了多搞几个这样的类给PSO,分别保存每一维的优化过程就是了!实现后发现有问题,蓝色的最优点居然会跑到fitness函数外面!幸亏这个保存图片的功能,不然还真发现不了这个bug呢!经过调试发现是因为复制列表时仅复制了引用,这样在种群继续进化时就直接导致最优点的值也变了!找到问题就好办了,用deepcopy复制列表就OK啦~
多维PSO的代码如下:
# Copyright (C) 2009, Ace Strong <acestrong@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id: pso.py,v 2.0 2009/02/02 10:00:45 ace Exp $
from random import uniform
from copy import deepcopy
class PSO:
def __init__(self, pop_size, particle_size, particle_scope, C1, C2, w, max_w, min_w, max_iter, func, extra_args=None):
'''
pop_size: size of population
particle_size: dimension of each particle
particle_scope: value range of each particle's dimension
C1: cognitive factor following personal best
C2: social facotr following global best
w: const inertial factor
min_w: min range of inertial factor
max_w: max range of inertial factor
max_iter: max iteration of algrithm
func: fitness evaluation function
'''
# fitness function
self.func = func
# used for fitness function
self.extra_args = extra_args
self.pop = []
# converging factor
self.r = 0.729
self.particle_size = particle_size
# parse range of each dimension
self.min_range = particle_scope[::2]
self.max_range = particle_scope[1::2]
# 0: position, 1: velocity, 2: fitness
for i in xrange(pop_size):
self.pop.append(self.initParticle())
self.evaluate()
# global best
self.gbest = deepcopy(self.pop[0])
# personal best, each partical has one
self.pbest = deepcopy(self.pop)
# weight following personal best, cognitive factor
self.C1 = C1
# weight following global best, social facotr
self.C2 = C2
# weight following current speed, inertial factor
self.w = w
# used by un-const method
self.max_w = max_w
self.min_w = min_w
# max iteration number
self.max_iter = max_iter
# current iteration number
self.curr_iter = 0
def initParticle(self):
particle = []
# position, in particle_size dimension
position = []
for j in xrange(self.particle_size):
position.append(uniform(self.min_range[j], self.max_range[j]))
particle.append(position)
# velocity, in particle_size dimension
velocity = []
for j in xrange(self.particle_size):
velocity.append(uniform(-1, 1))
particle.append(velocity)
# fitness
particle.append(0)
return particle
def update_velocity(self):
# linear descending w
w = self.max_w - self.curr_iter*((self.max_w - self.min_w)/self.max_iter)
# # fixed w
# w = self.w
# # nonlinear descending w, concave function
# w = (self.max_w - self.min_w)*(self.curr_iter/self.max_iter)**2 \
# + (self.min_w - self.max_w)*(2*self.curr_iter/self.max_iter) \
# + self.max_w
# # nonlinear descending w, concave function
# w = self.min_w*(self.max_w/self.min_w)**(1/(1+10*self.curr_iter/self.max_iter))
i = 0
for p in self.pop:
for j in xrange(self.particle_size):
p[1][j] = w * p[1][j] + uniform(0, self.C1) * (self.pbest[i][0][j] \
- p[0][j]) + uniform(0, self.C2) * (self.gbest[0][j] - p[0][j])
i += 1
def evaluate(self):
for p in self.pop:
p[2] = self.func(p[0], self.extra_args)
def move(self):
i = 0
for p in self.pop:
for j in xrange(self.particle_size):
p[0][j] += self.r * p[1][j]
if p[0][j] > self.max_range[j] or p[0][j] < self.min_range[j]:
self.pop[i] = self.initParticle()
break
# if self.func(self.gbest[0],self.extra_args)!=self.gbest[2]:
# print "error in move!"
i += 1
def run(self, update_func=None):
for i in xrange(self.max_iter):
print "current iter = %d" % self.curr_iter
if update_func:
update_func()
self.update_velocity()
self.move()
self.evaluate()
# current best of personal bests
cpbest = deepcopy(self.pbest[0])
for k in xrange(len(self.pop)):
if self.pop[k][2] < self.pbest[k][2]:
self.pbest[k] = deepcopy(self.pop[k])
if self.pbest[k][2] < cpbest[2]:
cpbest = self.pbest[k]
if cpbest[2] < self.gbest[2]:
# print "changing gbest from %s" % self.gbest
self.gbest = cpbest
# print "to %s" % self.gbest
# if self.func(self.gbest[0],self.extra_args)!=self.gbest[2]:
# print "error in run!"
# print self.gbest
self.curr_iter += 1
def __str__(self):
ret = ""
for i in self.pop:
ret += str(i) + "\n"
return ret
import pygame
import time
class PygamePrinter:
'''draw the given dimension's evolution
'''
def __init__(self, pso, w=400, h=300, dimension=0, extra_args=None):
self.calls = 0
self.w = w
self.h = h
self._init_pygame()
self.pso = pso
self.dimension = dimension
self.extra_args = extra_args
def _init_pygame(self):
self.screen = pygame.display.set_mode((self.w, self.h), 0, 8)
self.backcolor = (0, 0, 0)
self.funccolor = (255, 255, 255)
self.partcolor = (255, 0, 0)
self.elitecolor = (0, 0, 255)
def draw_point(self, color, x, y, size=3):
pygame.draw.rect(self.screen, color, (x - size, y - size, \
size*2, size*2))
def p2p(self, x, y):
return (x + 1) * 200, y * 300
def draw_func(self):
for i in range(self.w):
x = i / (self.w / float((self.pso.max_range[self.dimension] \
- self.pso.min_range[self.dimension]))) \
+ self.pso.min_range[self.dimension]
y = self.pso.func((x, self.dimension), self.extra_args)
rh = y * (self.h / 2.) + (self.h / 2.)
self.draw_point(self.funccolor, i, rh, 1)
def _draw_xy(self, color, x, y):
self.draw_point(color, (x + self.pso.max_range[self.dimension]) * self.w \
/ float((self.pso.max_range[self.dimension] - self.pso.min_range[self.dimension])), \
(y + 1)*self.h/2)
def draw_pop(self):
for i in self.pso.pop:
self._draw_xy(self.partcolor, i[0][self.dimension], i[2])
i = self.pso.gbest
self._draw_xy(self.elitecolor, i[0][self.dimension], i[2])
def __call__(self):
#time.sleep(0.5)
self.screen.fill(self.backcolor)
self.screen.lock()
self.draw_func()
self.draw_pop()
self.screen.unlock()
pygame.display.flip()
if self.calls % 2 == 0:
# print "call=%d" % self.calls
pygame.image.save(self.screen, "pso-%d.bmp" % self.calls)
self.calls += 1
import math
def testFunc(arg, extra_args):
x = arg[0]
return math.cos(x) * math.exp(math.sin(x)) * math.sin(x) / 1.5
def test():
import math
# func = lambda x:math.cos(x*math.sin(x*0.3)-x) / 1.5
# func = lambda x:math.cos(x) * math.exp(math.sin(x)) * math.sin(x) / 1.5
p = PSO(15, 1, (-4.5, 4.5), C1=2, C2=2, w=0.5, max_w=0.95, min_w=0.4, max_iter=20, func=testFunc)
printer = PygamePrinter(p)
p.run(update_func=printer)
# p.run()
print p
print p.gbest
if __name__ == "__main__":
test()