将Simulink模型移植到C#

最近工作中需要将一个比较复杂的Simulink模型用C#实现,着实花费了一番功夫,下面将移植的方法总结一下。

 模型的离散化

Simulink的模型可以是连续的,用复杂的ode Solver求解,Solver会自动调整每次运算的时间间隔,以达到最精确的结果。这样的模型很难移植,因此为了程序编写方便,先将Simulink的Solver改为Discrete(离散),并且设定为Fixed-Step,这样离散化了的模型就容易实现多了。

如果模型中包括一些Continuous(连续)的库模块的话,需要把它们都手工转换为响应的离散的模块,例如:



转换之后的模型的输出和原始的模型的输出可能会出现比较大的差别,这就需要调整离散模型的step size,以及各个模块的参数,直到连续模型和离散模型的输出一致。

我们可以分别将两种模型的输出保存到Workspace中的变量中,然后进行一致性比较。因为两种模型的时间间隔是不同的,因此不能直接进行数值上的比较,而需要将连续模型的输出按照离散模型的时间重新取样(简单的插值运算即可)。

在实际转换中我发现连续模型的Transfer Fcn(传递函数)模块比较难找到对应的离散模型,需要花费一番功夫。

模型的转化也可以试试Tool->Control Design->Model Discretizer,让Simulink自动进行离散转化,我的模型不知道为什么转化失败,所以只好进行手工转化了。

各个模块的输入输出

下面的工作就是将各个模块移植到C#中,首先通过Sinks中的To Workspace模块,将被移植模块的输入输出全部保存到一个变量中。如下图蓝色模块所示,将Velocity的输入输出都保存到simout变量中,并且SaveFormat设置为Array。


运行模拟之后,运行下面的命令将simout中的结果保存到test.csv文件中,为了和C#程序的输出进行比较,我将输出精度设为最大,保证没有任何进度的损失:

dlmwrite('test.csv', simout, 'delimiter', ',', 'precision', 20)

C#程序的编写

剩下的事情就是编写一个程序让其输入输出和test.csv中的输入输出一致。因为可能需要对程序进行多次调试,和进行多组输入输出的比对,所以最好用单元测试软件NUnit将这些测试工作自动化。关于这一节,在今后的文章中详述。

没有延时效果的模块可以用一个函数对其输入输出进行描述:

doube[] Do(double[] inputs);

也就是说,得到此模块的输入之后,将输入传递给此模块,就得到其输出了。

但是例如积分器和延时器之类输入输出之间有时间差的模块就比较麻烦了。这样的模块如果其输出没有连接到输入的话(形成回路),那么可以先计算其输入,然后计算其输出,所以也可以用上面的函数。如果输出连接到自己的输入话,那么要先计算输出,计算模块的输出时要使用模块的即时输入和模块内部的状态,然后通过输出再计算输入,并将输入的值传递给模块,更新模块的状态。例如要计算如下的模型:


这个模型中的积分器的输出又回到了自己的输入,因此形成了回路。这时需要先计算积分器的输出值p1,然后将此值加1得到p2: p2 = p1 + 1,然后将p2输入到积分器,积分器对p2进行累加,以得到积分器的下一个输出。所以这个模型的输出为:

0, 1, 3, 7, 15, 31, 63, 127, ...

关于这方面的内容,今后再写文章详述。


以己之长比他人之短

前不久给海月看病毒的照片时,发现一个白血球吃病毒的动画,非常形象也很易懂。最近海月如果不想吃蔬菜了,我就跟海月讲:不吃蔬菜血液就不能制造白血球,没有白血球身体里的病毒就会越来越多,最后就得去医院打针。海月只要一听这话就会大口大口地吃蔬菜了。
有时为了教育孩子不得不想想办法。同样为了孩子的教育问题有时会自寻烦恼。
当看到别的同龄的孩子画画很好了,或者比较会认字了,就会不由自主地和海月比较起来。而现在的海月画画呀认字呀都处在一种很随意的状态,不会很认真地去学。每次一教她,她就会说:别说了,我累。还不住地扣耳朵,好像想把我的声音从耳朵里挖出来。看到海月这种学习状态会不由自主地对海月不满,明明可以和她玩一会也懒得理她了。
为了调解心理平衡总要和海月爸爸一起探讨一番,找出海月的优点,以己之长比他人之短。比如海月比较会用电脑,能够熟练使用鼠标。海月比较有理解能力,看日剧的时候,海月虽然不懂也很认真地去看,用自己的方式理解剧情。海月对生命比较有概念,去年还总是会因为蚂蚁死了而哭,今年自己就会说:蚂蚁早晚是会死的。虽然有点自欺欺人,却是家庭和睦所不可或缺的良方。

 


海月大闹天宫之续

海月给妈妈折纸,不管折成什么样妈妈都把海月夸得心花怒放,结果越折越开心,就搞成这个样了。


无处下脚


不让妈妈找到海月


海月大闹天宫

以前早上都会听到小学生上学的声音,因为新型流感所有学校都暂时停课一周,现在早上异常安静。平时下午旁边的小操场总会有孩子练习棒球或骑车子,现在也没有了孩子们的身影。其实我觉得可以出去走动一下,但海月爸爸坚持要躲在家里,还说我不负责任,为了不背上历史的骂名,只有忍耐一下了。
海月倒也没有要出去,一定是天花的照片把她给吓到了。只是呆在家里每天大闹天宫,怎么收也收不干净,到头来比带她出去还累。
对于这次流感国内的各方面应急措施都很到位,日本网站也报道了温家宝见流感患者。经过上次非典,还是有很大的进步,吃一堑长一智。

找到个好地方


如此看书


新型流感就在身边

没想到日本的新型流感会蔓延的这么快,仅两天的功夫就上升到100多人,而且又离自己这么近,最初发现的患者离我们不到50公里,现在我们所在的市也有一人被确诊。
得到消息后第一反应就是尽量减少外出,海月爸爸为了教育海月不要再吵着出去玩,给海月讲了许多有关病毒的知识,还在网上找了病毒的照片。为了加大力度,把以前得天花的人的照片给海月看,效果非常明显。海月立即表态:我不出去了,妈妈也不许出去,爸爸出去买东西。
今天中午海月正在参加的体操班,儿童馆,以及区役所的儿童俱乐部也分分打来电话,通知活动暂停,先观察情况。
真希望能早点恢复以前的生活,以前每天忙忙碌碌的总想找一天在家里好好休息一下,现在真的能呆在家里了,却发现原来失去的生活是最宝贵的。

海月看牙

因为发现海月的牙龈有点红肿,所以前不久带海月去看了牙医,又顺便给牙齿涂了氟,日本的医生建议给孩子的牙齿涂氟,据说可以防止得虫牙。
海月当然是哭得不成样子,从医院出来后,我对海月说:让海月刷牙,海月总是不赶快刷,现在好了吧,要医生刷了。(涂氟就是用牙刷在牙齿上涂一层象牙膏一样的东西,和刷牙差不多)
海月说:小孩是这样的,大人是说干什么就干什么,小孩就是这样拖的。
我接着问:海月是大人还是小孩?
海月回答说:我是小孩呀。
我问:你什么时候长大呀?
海月想想说:我长不大的。
嗨,一个不想长大的海月。
藏猫猫

 
藏猫猫


TiddlyWiki的抽认卡插件

关于抽认卡

一个抽认卡(或称闪卡(英文:Flash Card))是一小块纸片,在学校里用来作辅助教学(主要是英语国家)。抽认卡可以用来记录词汇、历史事件时间、公式等等。使用抽认卡的目的主要是帮助记忆,提高学生的学习动机、以及在课堂上为学生提供多种感官的刺激。你在每个卡片上写下一个问题(同时在背面记下答案),用它们来测试自己,并根据你的测试、学习结果把它们进行排序、分组。

这种策略使得学习更有选择性,也就是:在一组的卡片越难,你就越要花时间复习这一组。于是,你就能节省很多学习时间。

※ 摘自维基百科

抽认卡程序

http://memorizable.com/ 就是采用类似抽认卡的方法帮助用户记忆的网站。他提供了javascript的源程序。

最近发现TiddlyWiki版本更新为2.5,并且集成了jQuery库,这两个我最喜欢的javascript程序最终结合到了一起,真令人兴奋。于是我将其稍作修改,写成了一个TiddlyWiki的插件,并且专门做了一个TiddlySite来演示其效果: http://hyry.dip.jp/kt/index.py?site=memory,关于插件的源程序可以在 {CodeLib} 中找到。同时TiddlySite也更新为2.5,调试正常之后将发布最新的代码。

这个抽认卡程序效果很酷,但是写得比较乱,如果有时间能用jQuery重写一个就好了。

 


海月的计策

一天吃中午饭的时候,海月让妈妈把自己的蔬菜汤热一下,而且还强调:要热烫一点。妈妈当时还以为海月长大了,想吃热的东西了。

就在还没有想清楚的时候,海月又说了:热烫了,我就可以在等它慢慢凉的时候只吃鸡蛋糕了。
爸爸妈妈这才明白海月的计策,恍然大悟。 

吃旋转寿司

  

在淡路岛

 

 

 


去了大阪城

现在的你对时间有了一点模糊的概念
还不能清楚地理解

在下雨阴天的日子里
虽然只是上午
可是因为天阴了起来
你会以为是晚上
于是问妈妈:
爸爸是不是快回来了,天都黑了

去大阪的时候坐了地铁
你见黑了下来便问:
天都黑了怎么还没到呀

虽然你不太懂时间的概念
可你有时会看着表说:
都12点了,快吃饭吧
偶尔还真的被你碰对了
以为你真的会看时间了

在大阪城 

在大阪城后院吃冰激淋