分油问题C语言及分压电路设计经验_第1页
分油问题C语言及分压电路设计经验_第2页
分油问题C语言及分压电路设计经验_第3页
分油问题C语言及分压电路设计经验_第4页
分油问题C语言及分压电路设计经验_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

设有大小不等的X,Y,Z三个无刻度的油桶,分别能够盛满油X,Y,Z(例如,X=8,Y=5,Z=3),并约定X>Y>Z。

初始时,仅X油桶盛满油,Y和Z油桶为空。要求程序寻找一种最少的分油步聚,在某个油桶中分出T升油(例如T=4)。

解:

令三个油桶的盛油情况为倒油过程的状态,则倒油过程就是状态变化的过程。为了记录倒油过程,程序引入倒油状态队列,

将倒油过程中产生的状态存储在队列中。队列的每个元素记录每次分油后各个油桶的分油后各个油桶的盛油量和倒油轨迹等有关信息。

程序反复从队列中取出第一个还未检查过的状态,对该状态下的每个油桶判断其是否可以倒出油,及是否可以倒进油。由于油桶没有刻度,

分油时只能将某个油桶倒满或倒空。程序分别按倒空或倒满两种可能的倒油动作执行不同的处理,产生新的倒油状态,

为避免某个倒油状态在队列中重复出现,程序只将未曾出现过的新状态及其倒油轨迹信息存入队列中,假定程序检查了相当多的状态后,

或能找到解,或能确定问题无解。倒油程序算法如下:

算法---无刻度油桶分油

{

输入各桶容量和目标容量;

将初始状态存入倒油状态队列;

设置其它初始值;

do

{

对状态队列中第一个还未检查的元素

在还未检查完每个倒出的桶且还未找到解且还未确定无解情况下循环

if(倒出桶有油)

在还未检查完每个桶且还未找到解且还未确定无解情况下循环

if(当前桶不是倒出桶且桶还有空)

{

确定本次倒油量;

在队列中检查倒油后的结果状态是否在队列中出现;

if(结果状态不在队列中出现)

{

将结果状态和轨迹信息存入队列;

if(有桶中的油达到目标容量)

设置找到解标志;

}

}

if(还未找到解)

{

修正队列第一个还未检查过的元素指针;

if(队列中的元素都已检查过)

设置无解标志;

}

}while(还未找到解且还未确定无解);

if(找到解)

{

根据倒油步聚的轨迹信息,形成倒油步聚序列;

输出倒油步聚序列;

}

}

倒油队列中的元素应包含下列信息:各桶的盛油量,该状态是从哪一个桶(源桶)倒向哪一个桶(目标桶)而形成的,

形成该状态的元素在队列中的位置。根据以上算法编写如下程序。程序代码如下:

#include<stdio.h>

#defineN100

#defineBUCKETS3

structele{

intstate[BUCKETS];/*各桶盛油量*/

intsbucket;/*源桶*/

intobucket;/*目标桶*/

intlast;/*轨迹元素在队列中的下标*/

}q[N];/*队列*/

intfull[BUCKETS];

inti,j,k,found,unable,wi,wj,v,targ;

inthead,tail;

voidmain()

{

/*输入各桶容量和目标容量*/

printf("Entervolumeofbuckets.");

for(i=0;i<BUCKETS;i++)

scanf("%d",&full[i]);

/*如要检查full[0]>full[1]>full[2],相应代码在此*/

printf("Entervolumeoftarg.");

scanf("%d",&targ);/*检查targ<=full[0]的代码在此*/

/*设置将初始状态存入倒油状态队列等初值*/

q[0].state[0]=full[0];

for(i=1;i<BUCKETS;i++)

q[0].state[i]=0;

q[0].sbucket=0;

q[0].obucket=0;

q[0].last=0;

found=unable=0;

head=tail=0;

do

{

/*对状态队列中第一个还未检查过的元素在还未检查完每个倒出的桶

且还未找到解且还未确定无解情况下循环*/

for(i=0;i<BUCKETS&&!found&&!unable;i++)

if(q[head].state[i]>0)/*倒出桶有油*/

/*在还未检查完每个油桶且还未找到解且还未确定无解情况下循环*/

for(j=0;j<BUCKETS&&!found&&!unable;j++)

if(j!=i&&q[head].state[j]<full[j])

{/*当前桶不是倒出桶且桶还有空*/

/*确定本次倒油量*/

if(q[head].state[i]>full[j]-q[head].state[j])

v=full[j]-q[head].state[j];

elsev=q[head].state[i];

wi=q[head].state[i]-v;

wj=q[head].state[j]+v;

/*在队列中检查倒油后的结果状态是否在队列中出现*/

for(k=0;k<=tail;k++)

if(q[k].state[i]==wi&&q[k].state[j]==wj)break;

if(k>tail)/*结果状态不在队列中出现*/

{

/*将结果状态和轨迹信息存入队列*/

tail++;

q[tail].state[i]=wi;

q[tail].state[j]=wj;

q[tail].state[3-i-j]=q[head].state[3-i-j];

q[tail].sbucket=i+1;

q[tail].obucket=j+1;

q[tail].last=head;

/*如有桶达到目标盛油量,则设置找到解标志*/

if(wi==targ||wj==targ)found=1;

}

}

if(!found)/*还未找到解*/

{

head++;/*修正队列第一个还未检查过元素指针*/

if(head>tail)/*队列中的元素都已检查过*/

unable=1;/*设置无解标志*/

}

}while(!found&&!unable);/*还未找到解且还未确定无解*/

if(found)/*找到解*/

{

/*根据倒油步聚的轨迹信息,形成倒油步聚序列*/

i=tail;

j=-1;

do/*原倒油步聚逆向链接,现改为正向链接*/

{

k=q[i].last;

q[i].last=j;

j=i;

i=k;

}while(j);

/*输出倒油步聚序列*/

for(k=q[k].last;k>=0;k=q[k].last)

{

printf("%5dto%2d:",q[k].sbucket,q[k].obucket);

for(i=0;i<BUCKETS;i++)

printf("%4d",q[k].state[i]);

printf("");

}

}

elseprintf("Unable!");

}

分油

我们首先用字母a,b,c代表8斤桶,5斤桶和3斤捅。规定倒油的顺序为:

a->b->c->a

并且必须符合如下规则:

1.b(5斤桶)倒空后才能从a(8斤桶)中取油。

2.c(3斤桶)盛满后才能向a(8斤捅)中倒油。

我们设从a中往b倒油x次,从c往a倒油y次,那么最后a中剩下的油应该为8-

5x+3y斤,按照题意,我们得到如下方程,

8-5x+3y=4:

我们为了得到这个方程的解,应按照上述的倒油规则不断的倒下去,直到a中或b中

油的重量为4斤为止,另外也可以改变倒油的规则,看能否找到最好的倒油步聚。代码:#include<stdio.h>

inti;

main()

{

inta,y,z;

printf("InputFulla,Emptyb,c,Geti:");

/*读入3个容器的容量和最后需要的数量*/

scanf("%d%d%d",&a,&y,&z,&i);

getti(a,y,z);

}

getti(inta,inty,intz)

{

intb=0,c=0;

/*b,c为二个容器的实际重量*/

printf("a%db%dc%d%4d%4d%4d",a,y,z,a,b,c);

while(a!=i||b!=i)

/*如果满足要求退出循环*/

{

if(!b)

/*如果b为空,从a往b倒油*/

{

a-=y;b=y;

}

elseif(c==z)

{

a+=z;c=0

/*如果c已满,从c往a倒油*/

}

elseif(b>z-c)

{

b-=(z-c);c=z;

/*如果b的重量大于c的剩余重量,倒满c*/

}

else

{

c+=b;b=0;

/*否则将b中的油全部倒入c*/

}

printf("%4d%4d%4d",a,b,c);

}

}运行结果:

InputFulla,Emptyb,c,

Geti:8534volume:a=8

b=5

c=3

start:8

0

0

3

5

0

3

2

3

6

2

0

6

0

2

1

5

2

1

4

3

4

4

0 前些天有人问我如何实现精密的分压,他认为电阻分压不够精密.其实分压的目的就是为了符合AD转换的输入范围,但其实有时候不但输入范围超出AD量程,甚至会是一个负电压,这个时候需要将电压平移.反正今天双休有空,我就说说自己的做法,疏漏之处敬请谅解现今大多数的AD芯片都采用单电源+5V、+3.3V甚至更低的+1.8V供电,其差模输入范围一般是±Vref(差分输入)、0~+Vref,部分允许使用外部基准的芯片允许0~VDD的输入范围,但是无论如何无法对一个负的输入电压进行AtoD的转换(也许有一些双电源的AD芯片可以,但我是个新手没仔细研究过)。如果要对一个过零的正负信号进行AD转换就必须进行电平的平移。理论上如图1所示的差分放大器就可以完成电平平移的效果,差分放大器的增益等于1,因此Vout=Vin+5.000。Vin=-5~+5V,因此经过平移后Vout=0~10V,再经过电阻R18、R19二分压到符合AD系统输入范围的电压。 但是图1所示的电路并不理想。第一,放大电路的输入阻抗约等于R16+R17=20K,低的输入阻抗要求信号源必须是低内阻具有衡压输出特性的信号源,否则将造成很大的误差;第二,R8R9R16R17的匹配程度将直接影响增益精度;第三,R18R19的二分压也将带来2%的最大误差,如果并非二分压那么R18≠R19,由于消耗的功率不一样导致R18温度与R19不相等,温漂将使得分压误差加大;第四,任何接入的电路将等效成一个负载,即使AD系统只吸收很低的电流,等效阻抗很大,也将进一步加大分压的误差。 对于第一个问题,可以在差分放大前加入一级电压跟随器作为缓冲,利用运放的高输入阻抗减少对信号源的影响,并且运放的低输出阻抗衡压输出的特性可以很好的满足差分放大级的“特殊”要求。对于第二和第三个问题,使用0.1%低温漂的精密电阻器可以大为改善。对于第四个问题,再运放负载能力允许的情况下使用阻值更小的电阻器可以将影响降低,但是应当注意的是-----使用阻值更小的电阻器将会使消耗功率增加,而消耗功率的增加又使得温度上升,温漂问题加重。经过改进的电路如图2所示: 当然,你还可以使用单片集成差分放大器去替换后端的用精密运放和精密电阻器构建的差分放大电路,例如单位增益的AMP03。其高共模抑制比(CMRR):100dB(典型值)、低非线性度:0.001%(最大值)、低失真:0.001%(典型值)、总增益误差0.0080%的性能是绝对优胜于分立器件构建的差分放大电路的。然而成本是否增加很多我就不知道了,我不是采购不知道价格,哈哈。图1图2 但是图2所示电路在处理一些幅度更大的信号会出现“瓶颈”。一般运放的摆幅在电源轨以内应留有2V的余量。以图2为例,电平平移以后输出0~10V,对于图2中±12V供电来说刚好可以满足,但是如果输入信号幅度更大±7.5V呢?那么即使运放工作在±15V的推荐最大工作电压下也无法满足,为了输出不失真的信号运放就只能工作在±18V的极限电源电压下了。那如果先电阻分压再跟随再作电平平移呢?不就可以很好解决么?我们看看下面的图三:圖3图3中电路只需改变R1R2的比例就可以很容易使输出符合AD系统的输入范围,并且由于先分压再作电平平移,因此输出的最大值就是AD系统允许的输入最大值,上述图2电路的“瓶颈”问题不再存在。为了尽量减少对信号源的影响,R1R2的值必须足够大,但是对于电压跟随器U2来说R1R2的分压网络相当于一个内阻等于R1//R2的信号源,因此U2的输入阻抗必须足够大。对于图3,即使U2等效阻抗高达100M,也将带来1%的误差,因此R1R2数量级的选择应该综合考虑信号源内阻和电压跟随器的输入阻抗。 如果要求更精密的的分压和电平平移是否有更好的办法呢?我们都知道一个高开环增益,低失调电压的运放只要将输出完全反馈到反相端就可以构成电压跟随器;那如果将输出完全反馈到单位增益的仪表放大器反相输入端呢?-----那就是一个精密的二分压电路!!因为[(Vin+)–(Vin-)]*G=Vout,而此时Vin-=Vout、G=1因此Vin+=2Vout,即Vout=1/2(Vin+)。并且由于失调误差也同时负反馈到反相端相减,因此仪表放大器的失调误差为原来的1/2。 对于±5平移到0~10V并且需要分压到0~5V的应用,图4的电路刚好能满足。他在电平平移的同时实现了精密的二分压。与图2、图3相比除了具有更高的精度之外,还具有更高的输入阻抗因此对信号源影响更小;

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论