2007年12月31日星期一
如何研究交通领域中的混沌现象
查了一个中午的文献,发现国内杂志的文章集中于如何快速的判定混沌,主要是研究交通流中的混沌现象,更具体的说来就是短时交通流预测,这也是我比较关注的一个方面。外文杂志的文章好多也是国人写的,交通流预测占了一个大头,还有其他的还没归纳出来。
2007年12月27日星期四
linux下中断方式读取串口数据
读取串口这样的工作当然不应该放在主线程中去做,开一个后台线程监控串口,有数据输入时接收完整的一帧,提取数据,然后传给主线程处理是比较合理的做法。Qt中提供了与平台无关的线程类QThread,线程间的通讯可以使用QEvent来进行。网上常见的读取串口数据的方式是在一个死循环中不断的查询(读取串口数据),这样显然是对cpu资源的浪费。使用中断方式是一个理智的选择。现在的问题就归结为如何在线程中使用中断方式来读取数据,然后用QEvent(其实是其子类)传回主线程。用QEvent传送数据比较简单,可以参见这里。用中断方式读取串口数据本是件再普通不过的事情了,但由于鄙人对linux下的串口编程不熟悉,颇是费了一番周折,最后终于在网上找到了解决方法,记录下来备忘~
实际上采用了linux串口的非同步式输入方式。具体说来,就是调用read操作后,立即返回,待完成后会发出讯号给设置好的回调处理函数,在回调函数里可以完成QEvent的发送。
给出一个例子代码:
#include
#include
#include
#include
#include
#include
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX 系统相容 */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status); /* 定义讯号处理程序 */
int wait_flag=TRUE; /* 没收到讯号的话就会是 TRUE */
main()
{
int fd,c, res;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
/* 开启装置为 non-blocking (读取功能会马上结束返回) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd <0)>
/* 在使装置非同步化前, 安装讯号处理程序 */
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* 允许行程去接收 SIGIO 讯号*/
fcntl(fd, F_SETOWN, getpid());
/* 使档案ake the file descriptor 非同步 (使用手册上说只有 O_APPEND 及
O_NONBLOCK, 而 F_SETFL 也可以用...) */
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* 储存目前的序列埠设定值 */
/* 设定新的序列埠为标准输入程序 */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* 等待输入讯号的回圈. 很多有用的事我们将在这做 */
while (STOP==FALSE) {
printf("./n");usleep(100000);
/* 在收到 SIGIO 後, wait_flag = FALSE, 输入讯号存在则可以被读取 */
if (wait_flag==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%s:%d/n", buf, res);
if (res==1) STOP=TRUE; /* 如果只输入 CR 则停止回圈 */
wait_flag = TRUE; /* 等待新的输入讯号 */
}
}
/* 回存旧的序列埠设定值 */
tcsetattr(fd,TCSANOW,&oldtio);
}
/*********************************************
* 讯号处理程序. 设定 wait_flag 为 FALSE, 以使上述的回圈能接收字元
**********************************************
void signal_handler_IO (int status)
{
printf("received SIGIO signal./n");
wait_flag = FALSE;
}
2007年12月17日星期一
关于车辆跟驰模型发展的一点思考(续)
讨论中提到了,不论哪一钟模型,模型的校准都是不能回避的、至关重要的环节。关于车辆跟驰的校准,显然用神经网络的方法最简单,不过这样得出的模型只能用于仿真,对于不仅仅需要仿真的应用,如我的应用中不仅要仿真,还要判断甚至预测是否发生碰撞,需要对驾驶行为进行深入研究的,神经网络的方法就不适用了。
我现在使用的模糊推理模型,分为Mamdani和TSK两种,前者更易于理解,在车辆跟驰建模中应用较多(反正我看到的都是用这种),但校准比较麻烦;后者在控制中应用较多,其特点是把整个输入空间分为若干个子空间,每个子空间内用线性表达式来描述输入和输出间的关系(理论上也可以用非线性的表达式,但这样就没啥意义了),计算速度快,校准相对简单。
我两个都用过,前者校准的效果始终不好,才想到用后者来试试,现在后者的校准程序还没编完,不知道效果能如何。不过真要使用后者的话,还需要好好看看讨论中提到应避免的问题,最好能兼顾驾驶行为的意义,这样才是完美~~
2007年12月16日星期日
关于车辆跟驰模型发展的一点思考
车辆跟驰模型发展的历程,一路看来,其根本目的就是对驾驶者的行为进行建模,使模型的输出和我们一般观察到的驾驶行为相符合。这样,就可以在交通仿真,尤其是微观交通仿真中,模拟驾驶员在设定的交通环境中的行为。这其实是有一定的风险的,车辆跟驰模型的输出与我们在有限次观察中的行为一致,并不一定可以外推出模型中特定交通环境中的输出与真实驾驶者在特定交通环境中的行为一致!但由于所谓的特定的交通环境和一般的交通环境有很多类似的地方,而驾驶员的驾驶行为是根据长期驾驶经验积累而成的,有一惯性和延续性,不会发生突变。所以用模型来模拟驾驶员在特定交通环境里的驾驶行为是可行的。
输入量和输出量的确认也是一个问题。输出量很好确认,就是驾驶员的加减速行为。输入量就不是那么明显了,除了明摆着的前后车距离,车速外,还有许多因素对 驾驶员的判断起影响作用,其中驾驶员的性格对驾驶行为有着比较大的影响。输入量少了,建立的模型与现实中观察到的行为不符合;输入量多了,模型会很复杂,而且有的输入量只对某些驾驶员起作用,这也增加了建模的难度。
来看看前辈们都做了哪些工作吧!:)
从GHR模型开始,先是尝试用当时建模的主流方法,通过数学公式来描述输入量与输出量之间的关系。根据对驾驶员驾驶决策产生机制的不同认识,选择不同的输入量,从而派生出了多种的模型。其中比较著名的有GHR模型(基于刺激反应原理),碰撞避免模型(基于安全车头间距),反应点模型(基于人的视野)。
后来随着人工智能的兴起,基于模糊推理、神经网络的建模方法迅速兴起。(待续)
BTW:
正如Boer所说,人类与机器在驾驶方面一个最大的不同是人可以从有限的几个感知量中得出驾驶所需的全部信息。在对车辆跟驰模型进行标定的跑车实验中,纵向距离、速度等可以直接度量的变量是容易获得的,而对驾驶者所能感知的变量,如角度、角度变化率等,还没有方便的方法来采集。那么,是不是就无法对模型进行标定了呢?非要等到可以采集到这些人类感知的变量才能继续工作呢?当然不是了!方法还是有的~~
虽然人类只能感知有限的几种输入量,但从驾驶员总结的驾驶经验不难看出,其中驾驶决策还是根据距离、速度等信息得出的!这是为什么呢?各种不同的变量实质上是从不同角度来描述车辆的行驶状态,人类从其中几个变量中获取的驾驶所需的信息,从另外几个变量中也能获得。而驾驶习惯表现在对不同的行驶状态,作出不同的反应,这与如何获得行驶状态的信息无关。以我自己的经验来看,新手刚开始学倒桩时,教练教的是看到几个点时做相应的动作;学员熟练以后,就可以找符合自己习惯的参考点,但动作还是相同的。而人类可以感知的几个变量,其实并不适合表达传递(所谓只可意会不可言传~),还是用距离、速度等信息来表示更符合习惯。当然了,信息在转换(传递)的过程中必然产生损失,但这不要紧,聪明的人类完全可以忍耐这些~~
常用linux命令的语法和功能
ls: 文件列表
wc –l file wc -w file wc -c file: 分别计算文件的行数(line)、单词数(word)和字符数(character)
cp sourcefile destfile: 文件拷贝
mv oldname newname: 重命名文件或移动文件
rm file: 删除文件
grep 'pattern' file: 在文件内搜索字符串或和正则表达式匹配的字符串
cut -b column file: 将指定范围内的文件内容输出到标准输出设备(屏幕)上。比如:输出每行第5至9个字符 cut -b5-9 file.txt,注意不要和cat命令混淆,这是两个完全不同的命令
cat file.txt: 输出文件内容到标准输出设备(屏幕)上
file somefile: 取得文件somefile的文件类型
read var: 提示用户输入,并将输入内容赋值给变量var
sort file.txt: 对file.txt文件所有行进行排序
uniq: 只输出文件中内容不一致的行,如: sort file.txt | uniq
expr: 进行数学运算,如要进行2+3的运算,命令为: expr 2 "+" 3
find: 搜索文件,如根据文件名搜索:find . -name filename -print
tee: 将数据输出到标准输出设备(屏幕) 和文件,比如:somecommand | tee outfile
basename file: 返回不包含路径的文件名,如: basename /bin/tux 会返回 tux
dirname file: 返回文件所在路径,如:dirname /bin/tux 会返回 /bin
head file: 打印文本文件开头几行
tail file : 打印文本文件末尾几行
sed: 是一个基本的查找替换程序。可以从标准输入(如命令管道)读入文本,并将结果输出到标准输出(屏幕);该命令采用正则表达式进行搜索。不要和 shell中的通配符相混淆。比如将 ubuntu 替换为 Ubuntu :cat text.file | sed 's/ubuntu/Ubuntu/' > newtext.file
awk: 用来提取文本文件中的字段。缺省的字段分割符是空格,可以使用 -F 指定其它分割符。cat file.txt | awk -F, '{print $1 "," $3 }',这里我们使用 , 作为字段分割符,同时打印第一和第三个字段。如果该文件内容为 Adam Bor, 34, IndiaKerry Miller, 22, USA,则上述命令的输出为:Adam Bor, IndiaKerry Miller, USA
2007年12月13日星期四
用python操作word
lp有求当然要比应了!在回来的车上就开始想该怎么整。用word界面的菜单功能,添加一个文件进来就要点数次鼠标,不好;用word的VBA功能,肯定能完成任务,不过VBA我不熟,看着那语法就头疼,不好;用python倒是不错,谁用谁知道,而且在邮件列表上看过有人用来操作excell,想必也一定能操作word,就用这个试试吧,搞不出来再用VBA也不迟。
回来以后就开始找操作word的库,google一下就找到了,叫win32com。照着网上的例子写了一个简单的脚本,居然出错了!找到出错的地方,注释掉,直到成功。发现错误的地方都是一些常量的使用,报错信息是没有该属性~先不管它了,还好我用不到什么常量。
新建文档没有问题,可是打开已有的文档总是报错,更令人郁闷的是错误信息全是16进制的代码,完全不明白哪里出了问题!忙乎了一个下午,试了N种可能,就是不行!以为是编码问题,找了半天怎么修改python的默认编码,成功后发现还是不行!又从命令行执行代码,居然成功了!比较两者的不同,发现命令行上由于不是在当前目录,所以写全了路径,可是从代码执行时也能通过'.\\'获得当前目录的文件列表啊?!不管,先加上全路径再说!
终于可以打开了,下面就是如何把一个文档里的内容拷贝到另一个文档的最后了~看了半天的VBA的帮助文件,终于成功了(中间的N多挫折就不说了)~~
然后给每个文档内容后后插入换行符,这需要常量wdPageBreak,没有,就直接查帮助其对应的值为7,填上就是~
lp那里没有装python,还要用py2exe打包为exe文件来发布~
不多说了,贴上代码:
#!/usr/bin/env python
#coding=cp936
import win32com
from win32com.client import Dispatch, constants
import os
import sys
#print sys.getdefaultencoding(), sys.getfilesystemencoding()
reload(sys)
sys.setdefaultencoding('cp936')
#print sys.getdefaultencoding(), sys.getfilesystemencoding()
def move2End(w, newdoc):
newdoc.Content.Select()
sel = w.Selection
sel.EndKey()
return sel
#获取当前目录
dirname = os.getcwd()+'\\'
filedir = dirname+'all\\'
# 读入单个文件列表
fileList = [f for f in os.listdir(filedir)]
# 读入文件顺序文件
f = open("order.txt", "r")
lines = f.readlines()
f.close()
#print lines
text = " ".join(lines)
fileOrder = text.split(',')
for i in range(len(fileOrder)):
order = fileOrder[i].strip("\n")
fileOrder[i] = order.strip()
print '指定排列顺寻为:', fileOrder
#fileOrder=range(1,len(fileList)+1)
#w = win32com.client.Dispatch('Word.Application')
# 或者使用下面的方法,使用启动独立的进程:
w = win32com.client.DispatchEx('Word.Application')
# 后台运行,不显示,不警告
w.Visible = 0
w.DisplayAlerts = 0
# 打开新的文件
newdoc = w.Documents.Add() # 创建新的文档
for order in fileOrder:
for f in fileList:
filenum = f.split('-')[0]
try:
if order==filenum:
# 将游标定位于newdoc的尾部
sel = move2End(w, newdoc)
# 插入换行符(wdPageBreak=7)
sel.InsertBreak(Type=7)
sel = move2End(w, newdoc)
# 打开要插入的文档
f = filedir + f
#print f
doc = w.Documents.Open(FileName=f)
doc.Content.Select()
w.Selection.Copy()
# 插入文字
sel.Paste()
# 关闭插入文档
doc.Close()
print f, ' is copied~'
except ValueError:
pass
# 关闭
newdoc.SaveAs(dirname+'all.doc')
newdoc.Close()
w.Quit()
print '完成!~~:)'
2007年12月10日星期一
关于matlab中ga工具箱自写函数的问题
一直忙乎到10点多钟,跟踪了ga执行过程,才找到一点感觉~~ 和我原来想的不同,fitness function里的输入变量就是编码后的染色体(我认为是x值了),这和jgap里的类似,估计所有的ga包中都类似。还有一个灵感来自options参数。我本以为这是ga使用的,想不通为什么每次都要在规定参数里包含它,现在看来,由于它是一个structure,而又是在matlab中,因此我可以把自己需要的额外参数放在options里,这样就不用额外加参数了。
今天中午要去考倒桩,吃完中饭就要走,早上这点时间就用来实践昨晚的想法了~~
2007年12月5日星期三
Qtopia-Core的qconfig参数
那么configure是如何处理-qconfig设置的参数的呢?打开configure文件,搜索qconfig,上上下下的看了一遍,发现问题了!原来对于qconfig设置的参数,只能处理预定义的五个,即minimal,small,medium,large和full。自定义的,如local之类,则完全不处理!而看网上和使用旧版本Qtopia-core的书上,说的都是用-qconfig local来实现,可能是版本不同导致的变化吧~~
知道了问题的根源,解决起来就简单了!方法可以有多种,一种就像前一个师弟一样,在qmouselinuxtp_qws.h中直接定义相关宏,这样的弊端一是改变了源代码,二是默认使用了full配置,想要裁剪的话还要手工在命令行加很多的选项,不推荐!另一种方法是把预定义的五个配置文件之一,如small,改为自己需要的配置,再用-qconfig small来指定配置,该方法避免了第一种方法的弊端,只是默认的small文件就没了,当然可以备份一个~~还有一种方法是修改configure文件,在五种预定义配置外加一个,如strong,这样只要再把配置存在文件qconfig-strong.h中就可以了,哈哈,够有个性的吧~~!
anfis,又一种选择
我原来主要是想看TS模型如何在FLT中构建,这部分内容很少,很快看完了。然后又看了下anfis,自适应神经模糊推理系统,它也是从输入输出数据构建FIS的一种方法,通过计算梯度向量,使用反向传播或者最小二乘预测或者两者结合来调节参数。它的一个已知的弱点是可能陷入局部最值,这恰好是GA的特长所在,所以我现在的工作还是有意义的~~
老板早上来问论文的事情了,我说最近就能出结果了,然后再和大家讨论论文的事。时间紧迫啊!!
2007年12月3日星期一
搞定windows下qt在Eclipse中的调试功能
首先要解决的是编译生成debug版本可执行文件时出现“cannot find -lqtmaind”的错误。上网搜了一下,发现这是因为缺少debug版本的库文件,只要在Qt的bin目录下运行“qtvars compile_debug”即可(也可以到开始菜单的Qt程序组里找到“Qt 4.3.2 (Build Debug Libraries)”命令运行)。不过在第一次编译时出现了错误,从错误信息没看出哪里有问题,往上拉一拉看,发现编译时include的路径内居然有MS的vs .net 2003,要知道我们是用MinGW来编译的,问题可能出在这里!打开环境变量设置,发现里面有lib变量,里面赫然就是vs .net 2003的路径,删掉所有相关的变量,确定后重新执行编译,这回可以了。
编译出了debug版本的可执行文件,又出现了“Error creating session”的错误。还是先上网搜索,发现可能是gdb设置的问题。我看了一下MinGW的bin目录,里面根本没有gdb文件!还好我装过Dev-C++,那里面是可以调试的,找到Dev-C++的bin目录,里面果然有gdb!
下面就是对Debug对话框的设置,首先在Main选项卡下选择debug下的可执行文件作为C/C++ Application,然后在Debugger选项卡下选择gdb Debugger作为Debugger,不要选择“Stop on startup at”,在Debugger Option里选择前面找到的gdb文件即可。
搞定!!
不过gdb的调试功能好像是简单了一点,连Qt字符串的内容也看不到,调试的时候估计还要用print~~
新的模型,新的开始
上个月一直在做fuzzy model的参数优化(标定),尽管采用了种种手段,效果却是让人沮丧!后来偶然看到关于mamdani和TS模型之间异同的比较,犹如黑暗中的一盏明灯,让我重新燃起了希望~~之后的几天一直在看如何用输入输出数据来identify TS fuzzy model's structure and parameters。用了几天时间弄清了一篇论文中的算法,准备用matlab实现。又用了几天编写流程,用伪代码大致写了出来。有一处公式不会推导,麻烦lp帮忙看了一下,推导出来了,不过发现我们推导出的结果和论文中的不一样,有可能是论文错了,但对最后结果没有大的影响。这个礼拜就要赶紧写出来,看结果如何,理想的话就将之用于我的工作中,然后出文章。