Identity Of Code

هیچی و همه چی

Identity Of Code

هیچی و همه چی

ادغام و انتگرالگیری عددی | NUMERICAL INTEGRATION

انتگرالگیری عددی  | numerical integration
در شبیه سازی های فیزیکی/حرکتی ما معمولا با سه کمیت اصلی برداری موقعیت،سرعت و شتاب و سر و کار داریم که 
طبق قوانین و معادلات فیزیکی آقای ایزاک نیوتن(روحش شاد)حرکت رو پیاده میکنیم.
روش های گوناگونی برای پیاده سازی حرکت و ادغام این کمیت ها وجود داره،ساده ترین و معمول ترین روش ،روش 
Euler هست،اما این روش به اندازه کافی دقیق نیست و معمولا برای اپلیکیشن ها و گیم های ساده به کار میره ...
روش های پیاده سازی که ما اینجا بهش میپردازیم اینا هستن:
Euler
Verlet
RK2
RK4
چرا  روش اویلرخوب نیست ؟
شبیه سازی اویلر شاید تو نگاه اول خیلی عالی به نظر برسه، و هیچ مشکلی نداره،اما وقتی حرکت رو تو دنیای واقعی با حرکت شبیه سازی شده مقایسه میکنیم ،تفاوت زیادی احساس میشه 

 
 نمودار حرکت اویلر همونطور که تو عکس مشخصه دارای دقت کمتر،بریدگی و گسستگی شدید هست

اویلر ساده ترین روش پیاده سازی رو داراست اگر dt را تغیرات زمان در نظر بگیریم وx رو موقعیت،a را شتاب و v رو سرعت ،طبق این رابطه حرکتمون رو پیاده سازی میکنیم:
 x=v*dt+x
v=a*dt+v
توجه داشته باشیم که این روش متداول ترین روشه و معمولا برای کار های نه چندان پیچیده خوب جواب میده،

روش Runge-Kutta
این روش به اختصار rk شامل دو زیرشاخه دیگه rk2و rk4 هست که دقت rk4 بیشتره و معمولا هم به این نام میشناسنش
rk2نسبت به اویلر دقیق تر ولی ضعیف تر از rk4 هست و معمولا با نام های اویلر بهبود یافته یا improved euler یا midpoint euler هم میشناسنش،تو 
RK2:
طبق این روش ،سرعت و شتاب کنونی شی رو میگیریم و با سرعت و شتابی که مایلیم اعمال بشه جمع و میانگین رو محاسبه میکنیم و در آخر اون رو اعمال میکنیم،
x1و v1 موقعیت کنونی شی مون هست

 

a1=getAcc(x1,v1)*
x2=x1+v1*dt
v2=v1+a1*dt
a2=getAcc(x2,v2)
x1+=(v1+v2)/2*dt
v2+=(a1+a2)/2*dt

*getAccتابعی هست شتاب رو برمیگردونه.
RK4:
این روش دقیقتر اما پیچیده تر از روشهای قبلی هست یعنی تقریبا 4 بار عملیات قبل رو انجام میدیم،با محاسبه کردن شتاب-سرعت تو مقاطع مختلف و میانگین گرفتن درصد دقت رو بالا میبریم:


a1=getAcc(x1,v1)
x2=x1+v1/2*dt
v2=v1+a1/2*dt
a2=getAcc(x2,2)

x3=x1+v2/2*dt
v3=v1+a2/2*dt
a3=getAcc(x3,v3)

x4=x1+v3*dt
v4=v1+a3*dt
a4=getAcc(x4,v4)
x1+=(v1+v2*2+v3*2+v4)/6*dt
v1+=(a1+a2*2+a3*2+a4)/6*dt


اگر دقت کنیم در مرحله اول و چهارم مقادیر به طور معمول گرفته و محاسبه شده ،اما در مرحله دو و سه مقادیر تقسیم بر 2 شده و تو محاسبه میانگین باز در دو ضرب شده و در آخر به جای اینکه تقسیم بر 4شه تقسیم بر 6 شده،اینکار باعث میشه که یه وسط و انتهای منحن حرکتمون یه وزن خاصی داشته  و دقیقتر باشن.
باید توجه داشت که این روش یک ابزار با ارزش برای شبیه سازی های دقیق/پبچیده هست،و همچنین stable نسبت به روش اویلر،اما میتونه مشکلات performance و بهینه نبودن از لحاظ پردازش رو بهمراه داشته باشه.

روش Verlet
این روش که تلفظ میشه ver-lay به اندازه rk دقیق نیست، اما معمولا از اویلر دقیقتره، از این متد معمولا   برای ساخت سیستم های ""rag doll یا انیمت کردن کاراکتر ها،و در کل برای پیاده سازی فیزیک کاراکتر استفاده میشه، | تقریبا مثل عروسک خیمه شب بازی که اجزای مختلف عروسک به هم وصل هستن ومیتونیم تحت کنترل داشته باشیمش|.

در این روش ما با مفهوم متداول سرعت سر و کار نداریم، اما به جاش از موقعیت قدیمی oldlocation و موقعیت کنونی currentLocation  برای محاسبه سرعت استفاده میکنیم؛که سرعت برابر است با تفاضل این دو متغیر،منطق خیلی ساده ای داره ، اگر cl رو موقعیت کنونی و ol رو موقعیت قدیمی و tmp یک حافظه کمکی در نظر بگیریم داریم:

tmp=cl
v=cl-ol
x+=v
ol=tmp

این روش معمولا frame-based هست یعنی ما با عنصر زمان به اونصورت سر کار نداریم، اما سیستمی داریم که فریم به فریم رندر/محاسبه میشه.
برای تغیر دادن سرعت باید چه کنیم ؟ گفتیم که سرعت برابر هسا با  v=cl-olفرض کنید میخوایم یه مقداری مثل |nv|newVelocity  رو به سرعت سیستممون اختصاص  بدیم:
ol=cl-nv
اینجا هم پیاده سازی رو تو زبان اکشن اسکریپت انجام دادم:

              //Euler Integration

              private function euler(ball:Ball,dt:Number): void {

              ball.loc=ball.loc.addScaled(ball.velo, dt)

              ball.velo=ball.velo.addScaled(

              getAcceleration(ball.loc), dt)

              }

              //RK4 Integration

              private function rk4(ball:Ball,dt:Number) : void {

                    

              var a1:Vec2=getAcceleration(ball.loc)

              var p2:Vec2=ball.loc.clone()

              p2.incScale(ball.velo.scaleOf(1/2), dt)

             

              var v2:Vec2=ball.velo.clone()

              v2.incScale(a1.scaleOf(1/2), dt)

             

              var a2:Vec2=getAcceleration(p2)

              var p3:Vec2=ball.loc.clone()

              p3.incScale(v2.scaleOf(1/2), dt)

             

              var v3:Vec2=ball.velo.clone()

              v3.incScale(a2.scaleOf(1/2), dt)

             

              var a3:Vec2=getAcceleration(p3)

              var p4:Vec2=ball.loc.clone()

              p4.incScale(v3, dt)

             

              var v4:Vec2=ball.velo.clone()

              v4.incScale(a3, dt)

             

              var a4:Vec2=getAcceleration(p4)

             

              ball.loc.inc(

              (ball.velo.addOf(v2.scaleOf(2))

              .addOf(v3.scaleOf(2)).addOf(v4))

              .scaleOf(1/6*dt)

              )

              ball.velo.inc(

              (a1.addOf(a2.scaleOf(2)).addOf(a3.scaleOf(2))

              .addOf(a4))

              .scaleOf(1/6*dt)

              )

      

              }

نظرات 1 + ارسال نظر
اسطوره چهارشنبه 29 آبان 1392 ساعت 20:51 http://oos2re.blogsky.com

به به استاد گرانقدر
خیلی خوبه
جدی میگم
عالیه

ممنونم، شما لطف داری

برای نمایش آواتار خود در این وبلاگ در سایت Gravatar.com ثبت نام کنید. (راهنما)
ایمیل شما بعد از ثبت نمایش داده نخواهد شد