66文章网, 最全、最新、最实时的知识分享平台!

化学实验方案设计和实验现象的分析/实验三 连续时间LTI系统的时域分析实验报告 39

作者: | 人气:2 | 时间:2017-11-23

一 : 实验三 连续时间LTI系统的时域分析实验报告 39

实验三 连续时间LTI系统的时域分析

一、实验目的

1、学会使用符号法求解连续系统的零输入响应和零状态响应

2、学会使用数值法求解连续系统的零状态响应

3、学会求解连续系统的冲激响应和阶跃响应

二、实验原理及实例分析

1、连续时间系统零输入响应和零状态响应的符号求解

连续时间系统可以使用常系数微分方程来描述,其完全响应由零输入响应和零状态响应组成。MATLAB符号工具箱提供了dsolve函数,可以实现对常系数微分方程的符号求解,其调用格式为:

dsolve(‘eq1,eq2…’,’cond1,cond2,…’,’v’)

其中参数eq表示各个微分方程,它与MATLAB符号表达式的输入基本相同,微分和导数的输入是使用Dy,D2y,D3y来表示y的一价导数,二阶导数,三阶导数;参数cond表示初始条件或者起始条件;参数v表示自变量,默认是变量t。通过使用dsolve函数可以求出系统微分方程的零输入响应和零状态响应,进而求出完全响应。

2、连续时间系统零状态响应的数值求解

在实际工程中使用较多的是数值求解微分方程。对于零输入响应来说,其数值解可以通过函数initial来实现,而该函数中的参量必须是状态变量所描述的系统模型,由于现在还没有学习状态变量相关内容,所以此处不做说明。对于零状态响应,MATLAB控制系统工具箱提供了对LTI系统的零状态响应进行数值仿真的函数lsim,利用该函数可以求解零初始条件下的微分方程的数值解。其调用格式为:y=lsim(sys,f,t),其中t表示系统响应的时间抽样点向量,f是系统的输入向量;sys表示LTI系统模型,用来表示微分方程、差分方程或状态方程。在求解微分方程时,sys是有tf函数根据微分方程系数生成的系统函数对象,其语句格式为:sys=tf(a,b)。其中,a和b分别为微分方程右端和左端的系数向量。例如,对于微分方程

a3y'''(t)?a2y''(t)?a1y'(t)?a0y(t)?b3f'''(f)?b2f''(t)?b1f'(t)?b0f(t) 可以使用a?[a3,a2,a1,a0];b?[b3,b2,b1,b0];sys?tf(b,a)获得其LTI模型。注意,如果微分方程的左端或者右端表达式有缺项,则其向量a或者b中对应元素应该为零,不能省略不写。

3、连续时间系统冲激响应和阶跃响应的求解

在连续时间LTI系统中,冲激响应和阶跃响应是系统特性的描述。在

MATLAB中,对于冲激响应和阶跃响应的数值求解,可以使用控制工具箱中提供的函数impulse和step来求解。

y?impulse(sys,t)

y?step(sys,t)

其中t表示系统响应的时间抽样点向量,sys表示LTI系统模型。

三、实验环境

本次实验使用的是Matlab软件,连续时间系统可以使用常系数微分方程来描述,其完全响应由零输入响应和零状态响应组成。MATLAB符号工具箱提供了dsolve函数,可以实现对常系数微分方程的符号求解,MATLAB控制系统工具箱提供了对LTI系统的零状态响应进行数值仿真的函数lsim函数,冲激响应和阶跃响应的数值求解,可以使用控制工具箱中提供的函数impulse和step来求解对某些函数进行验证和画图。

四、实验内容

1、已知系统的微分方程和激励信号,使用MATLAB命令画出系统的零状态响应和零输入响应(零状态响应分别使用符号法和数值法求解,零输入响应只使用符号法求解)。要求题目2必做,题目1选做。

解:

(2)零状态响应:

符号法:

eq1='D2y+4*Dy+4*y=Df+3*f';

eq2='f=exp(-t)*heaviside(t)';

cond='y(-0.001)=0,Dy(-0.001)=0';%求零状态响应

yzs=dsolve(eq1,eq2,cond); %符号求解

yzs=simplify(yzs.y)

ezplot(yzs,[0,10]);grid on

title('符号法求零状态响应') %输出符号法求零状态响应

结果:

yzs =

-(heaviside(t)*(t - 2*exp(t) + 2))/exp(2*t)

符号法求零状态响应

0.35

0.3

0.25

0.2

0.15

0.1

0.05

012345

t678910

数值法:

t=0:0.001:10;%取间隔

sys=tf([1,3],[1,4,3]);%表示出系统微分方程

f=exp(-t).*heaviside(t);%表示激励信号

y=lsim(sys,f,t);%零状态响应

plot(t,y),grid on

xlabel('Time');

ylabel('f(t)');

title('零状态数值法');

零状态数值法

0.4

0.35

0.3

0.25

f(t)0.2

0.15

0.1

0.05

0012345

Time678910

零输入响应:

符号法:

eq='D2y+4*Dy+4*y=0'; %求零输入响应

cond='y(0)=11,Dy(0)=22'; %随意制定的起始条件

yzi=dsolve(eq,cond); %符号求解

yzi=simplify(yzi)

ezplot(yzi,[0,10]);grid on %输出符号法求零输入响应

title('符号法求零输入响应');

结果

yzi =

(11*(4*t + 1))/exp(2*t)

符号法求零输入响应

10

9

8

7

6

5

4

3

2

1

012345

t678910

2、已知系统的微分方程,使用MATLAB命令画出系统的冲激响应和阶跃响应(数值法)。要求题目2必做,题目1选做。

解:

(2)t=0:0.001:10;

sys=tf([0,1,0],[1,2,2]);

f1=impulse(sys,t);

subplot(2,1,1)

plot(t,f1),grid;

xlabel('t');

ylabel('f1(t)');

title('冲激响应');

subplot(2,1,2)

plot(t,f2),grid;

xlabel('t');

ylabel('f2(t)');

title('阶跃响应');

实验三 连续时间LTI系统的时域分析实验报告 39_时域分析

冲激响应

1

0.5

f1(t)

-0.50123456

t

阶跃响应78910

0.6

0.4

f2(t)0.2

-0.2012345

t678910

五、实验思考

本次实验让我学会运用符号法求解连续系统的零输入响应和零状态响应,数值法求解连续系统的零状态响应,并且求解连续系统的冲激响应和阶跃响应。这次又多学会了几个新函数的表示方法,同时也能够更加熟悉地使用这个软件。本次还加强了同学之间的合作,受益匪浅。

二 : pthread_once实现简析

想到这个主题,也是由于最近在写自己的开源代码时,发现使用的singleton类是线程不安全的,虽然在应用主线程都已确保了初始化的正确性,但从一个通用库的角度来讲,这么做就无法保证使用者不出问题,也限制了自由度,pthread_once就是解决这个问题的一个良方,不过首先我们还是先从一些基本的singleton实现说起。(www.66460.com)

网上关于singleton类的实现真是一搜一箩筐,从最简单的说起(注:为了代码简洁,以下均不使用模板)

一)直接返回 local static 对象

class foo_t{public: static foo_t& instance() { static foo_t foo; return foo; } };

这就是最简单的singleton使用,这里有一个小问题就是:foo对象必须以 local static 的形式存在,关于这一点在《Effective C++》一书中Scott Meyers大神已经说明原因,non-local static 变量的初始化顺序存在不确定性,而 local static 变量的初始化时机是可知的。

不过这种写法也有问题,就是多线程环境下无法保证其正确性,因为当 static foo_t foo; 在运行时第一次达到时,相对应着的是多条指令,就像是类似下面的情况:

if (!foo_init_flag){ foo = foo_t(); foo_init_flag = true;}

当同时多个线程调用instance()时,对于foo对象的正确初始化,就无法得到保证了。

一个解决方法是将所有单例类在主线程启动时进行统一的初始化,这个方法也是最有效和最简单的。

当然如果你使用的是c++ 11,就不必为此烦恼了,c++ 11 的 local static 变量初始化已经是多线程安全的了,也即是说,如果你希望你的应用现在,将来只会在 c++ 11上运行的话,就目前看来这种直接返回 local static 的方法或许会是你最简单有效的方案,如果你希望你的应用更具移植性和跨平台性,那么请继续往下看。

二)每次 get_instance() 时都进行lock

为了解决上面提到的多线程安全的问题,可以在 get_instance() 方法中进行锁保护,

static foo_t& instance() { mutex_t lock; // do init... ... return foo; }

这样做当然可以解决问题,但效率的损失显而易见,所以这个方案除了做demo,肯定不能应用到真实环境,pass之~

三)使用 double checked locking pattern(DCLP)机制

最早人们都使用这种方案来保证正确性而且能不失效率,我们先来看一下实现代码:

class foo_t{public: static foo_t& instance() { if (NULL == foo) // 1 { mutex_t scope_lock(mutex); { if (NULL == foo) // 2 { foo = new foo_t(); } } } return *foo; } private: static foo_t *foo; mutex_t mutex;};foo_t* foo_t::foo = NULL;

当多个线程同时首次进入 instance(),都会发现 1处 为真,之后则开始竞争互斥锁,竞争得到锁的线程会进行初始化,然后释放锁,之后其他线程在拿到锁之后,会在 2处 再进行一次check(这里已是串性化地进行check),这时发现实例已被初始化,则直接返回实例,整个过程看似毫无纰漏,但meyers大神又在这时给了众人当头一棒:http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf

在此文中meyers清楚地阐述了在c++中这种做法的危险性,在第3页第4页中,meyers指出 new Singleton; 这一个步骤在真正运行时会分解成三个行为:

Step 1: Allocate memory to hold a Singleton object.
Step 2: Construct a Singleton object in the allocated memory.
Step 3: Make pInstance point to the allocated memory.

也即是:

1. 分配内存

2. 构造foo对象

3. 将指针指向分配的内存

但就是这三个行为,可能会被cpu指令重排,然后执行的顺序发生了变化,例如:3 => 1 => 2

这在通常情况下不会有什么危险,因为乱序执行就是cpu的一种优化手段,而且在外层有互斥锁的保护,但问题就在于,我们的互斥锁的保护是有条件的,也就是 foo 对象必须为空,而这个条件却被步骤3所影响,倘若cpu先执行了步骤3,这时另一个cpu同时进行 1处的判断,发现指针已不为空,直接返回对象供上层使用,而这时你返回的却是一个根本还没构造完毕的对象!其后果就不得而知了,但一定不会是你希望的那样。。。

那解决方法呢?memory barrier登场~,也即是我们俗称的内存屏障,它作为一个“界线”,来告诉cpu和编译器不要对这条界线前后的指令做调换,由于cpu和编译器都可能进行重排,所以我们需要保证这两者都不会对我们不允许进行重排的代码进行重排,这就需要内存屏障来完成。

注:文中meyers还提到了volatile关键字也无法解决问题,详细原因大家可仔细研究其论文,这里不再展开,值得注意的是,在vs2005上,volatile关键字可以解决 DCLP 问题,因为微软对于volatile的实现让其隐含了memory barrier的语义。

四)终于到猪脚 pthread_once 了,它可以在任何平台上保证你的 多线程安全的singleton类的正确性,函数的本意就是只运行某个函数一次,使用代码就不贴了,网上随处可寻,这里直接进入源码一窥究竟,看看 pthread_once 到底是如何解决 DCLP 所没有解决的问题的:

int__pthread_once (once_control, init_routine) pthread_once_t *once_control; void (*init_routine) (void);{ /* XXX Depending on whether the LOCK_IN_ONCE_T is defined use a global lock variable or one which is part of the pthread_once_t object. */ if (*once_control == PTHREAD_ONCE_INIT) { lll_lock (once_lock, LLL_PRIVATE); /* XXX This implementation is not complete. It doesn't take cancelation and fork into account. */ if (*once_control == PTHREAD_ONCE_INIT) { init_routine (); *once_control = !PTHREAD_ONCE_INIT; } lll_unlock (once_lock, LLL_PRIVATE); } return 0;}

P.S. 这段代码是glibc-2.9版本中x86 平台上pthread_once的实现,由于cpu指令重排(cpu order)的问题牵涉到硬件架构,所以这里我们只看x86平台。

在你看过了这段代码之后,你可能会心里嘀咕一番,“这不就是 DCLP 机制吗?和我们自己实现的有什么两样??”,没错,我在刚找到这份代码时,也百思不得其解,经过痛苦地google查阅资料之后,发现秘密就在于 lll_lock 之中,其实现是一个基于 gcc内嵌指令的宏,所以也依赖于不同的硬件架构,由于过长,我这里只贴出x86平台上的关键代码:

#define lll_lock(futex, private) \__asm __volatile (__lll_lock_asm_start \ ... // 省略了其他指令 ... // 省略了其他指令 : "memory");

memory是一个内嵌指令,作用是告诉gcc编译器:

1)不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕
2)不要将变量缓存到寄存器,因为这段代码可能会用到内存变量,而这些内存变量会以不可预知的方式发生改变

说白了,它就是一个针对编译器的内存屏障,这就保证了编译器不会对我们的代码进行重排,那么CPU重排呢?这memory指令就不会关心了,但这也无需我们去操心,因为在x86/x64平台上硬件体系已对此做了保证,有兴趣的朋友可能看看这篇文章:http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

所以,我们上面的 DCLP 事例代码,即使没有使用的lock并不具备barrier/fence,只要在x86/x64平台上,依然可以保证正确性(当然,其他不保证这一点的硬件体系下,需要加入内存屏障来保护,貌似powerPC就需要如此)。

之后我又去查看了早期版本(glibc-2.1)的pthread_once实现,发现当时没有加入lll_lock族,而是直接使用的pthread_mutex_xxx,经过查阅之后,了解到大多具有同步语义的 pthread操作已经带有屏障功能,具体参见:

#tag_04_11

http://www.hpl.hp.com/personal/Hans_Boehm/misc_slides/reordering.pdf

通过上面两篇文章,可以得出一个结论就是:假设我们的 DCLP 代码使用的是pthread_mutex_lock/unlock,那么就不会发生问题,但这样做不太符合应用开发者“面向接口编程”的理念,毕竟从理念上来讲 lock 和 barrier/fence虽然关系微妙,但却并不一定存在包含关系(从meyers的论述中即可知),某些时候,我们应该抱着“无知”的态度去使用它们。

综上所述,要写一个线程安全的singleton,pthread_once是值得我们信赖的帮手,即使你不了解底层硬件体系,编译器,它也能完成你希望的,这里附上一个我的chaos库中的实现:https://github.com/lyjdamzwf/chaos/blob/dev/chaos/utility/singleton.h

最后做一下总结:

*) local static变量不是多线程安全的,而c++ 11中的local static是多线程安全的

*) double checked locking pattern(DCLP)存在out-of-order问题,需要提供内存屏障来保证 编译器/CPU 不会“打乱”你的代码

*) x86/x64平台上DCLP不会出现问题,但这只是解决了cpu重排问题,对于编译器重排我们还要进行保证

*) pthread中的同步操作都具备 屏障(cpu和编译器) 功能

新年愉快 :)

-EOF

三 : 为了证明铁和硫反应产物中铁的化合价,下面是某同学设计的实验过程的?

为了证明铁和硫反应产物中铁的化合价,下面是某同学设计的实验过程的一部分: (4)操作②的作用是_

为了证明铁和硫反应产物的化合价,下面是某同学设计的实验过程的一部分:


(4)操作②的作用是________,反应方程式是________,也可改用________;

反应方程式是S和KOH生成K2S和K2SO3和H2O为什么能这样反应?


氯能在碱中岐化,硫也可以滴。

目的是除掉多余的硫,这是很明显的。

倒是“也可改用”值得考虑,取巧的答案是NaOH,或者K2CO3。是不是还可以用CS2或者乙醇等有机溶剂溶解多余的硫?感觉Na2S溶液形成Na2Sx(x=2,3,4,...多硫化物),不太可靠,因为多硫化物还有氧化性,理论上有可能进一步氧化处于化合态的铁。

四 : 珠海实验中学教师的待遇不算财政上发的工资,实验中学的课时费和福利

珠海实验中学教师的待遇

不算上发的工资,实验中学的课时费和福利高吗? 大约有几多?


珠海的实验中学有两个

一个是市属的“市实验中学”

一个是区属的“香洲区实验中学”

财政工资都一样,没有课时费,除了平时的补课费外,基本都没有什么福利。

市实验中学的教学质量和生源相对好一点