Tại sao tích hợp quá mức tích lũy?


14

Tôi đang bắt đầu tìm hiểu cách vật lý DIY và tôi có một câu hỏi về việc triển khai tích hợp ở mức cơ bản nhất (nghĩa là đây không phải là câu hỏi Euler so với RK4).

Gần như mọi ví dụ tôi gặp đều có một số integrate()chức năng lấy dấu thời gian kể từ lần cập nhật trước và cập nhật gia tốc (và / hoặc vận tốc và / hoặc vị trí) kể từ lần cập nhật cuối cùng.

Ở dạng đơn giản nhất: position += velocity * deltaTime

Tuy nhiên, tôi không hiểu tại sao nó lại tích lũy như thế này khi nó có thể dễ dàng nhận được bằng cách thay đổi một chức năng . Ví dụ: getPosition = makeNewFunction()có thể trả về một cái gì đó có chữ ký Time -> Positionvà hoạt động bên trong của hàm đó được tạo thông qua công thức toán học thích hợp.

Theo cách đó, không có sự tích lũy ... bất cứ khi nào vị trí cần được nhận, nó sẽ gọi chức năng đó với thời gian hiện tại.

Người mới hiểu của tôi là điều này cũng sẽ tránh được các lỗi xuất phát từ tích lũy ... vậy tại sao điều này không hoạt động, tôi còn thiếu gì?

(fwiw tôi đã đặt cùng một bằng chứng cơ bản của khái niệm về idea- này mặc dù nó cũng thử nghiệm một vài thứ khác cùng một lúc do đó, nó không phải là ví dụ sạch: https://github.com/dakom/ball-bounce-frp )

EDIT 1: như đã đề cập trong các bình luận, có lẽ điều quan trọng là chỉ ra rằng tôi chưa học về thay đổi gia tốc, hoặc xử lý giật và những thứ khác đòi hỏi tích hợp bậc cao hơn tăng tốc liên tục.

EDIT 2: đây là một số mã mẫu cơ bản của ý tưởng và cú pháp javascript giả - lưu ý getKinematicPositionđược áp dụng một phần để nó trả về một chức năng mới chỉ là Thời gian -> Vị trí:

Tôi đang giữ vị trí ở đây nhưng nó có thể là một cái gì đó khác, như getVelocity, tôi đoán ...

getKinematicPosition = initialVelocity => acceleration => time => 
  ((.5 *acceleration) * (time * time)) + (initialVelocity * time);

getPosition = getKinematicPosition ([0,0,0]) (GRAVITY);

onTick = totalTime => {
   position = getPosition (totalTime);
   onCollision = () => {
     getPosition = changeTheFunction(totalTime);
     //changeTheFunction uses totalTime to base updates from 0
     //it could use getKinematicPosition or something else entirely
   }
}

1
Chức năng của bạn sẽ làm gì, nếu bạn có tốc độ / gia tốc không đổi?
Linaith

Tôi không có ý kiến! : D Nếu đó là lý do - ví dụ: tôi chưa thay đổi khả năng tăng tốc, tôi thực sự đánh giá cao lời giải thích đầy đủ hơn về việc điều này sẽ phá vỡ như thế nào (nếu không tôi có thể đi vào con đường chức năng này và đi vào ngõ cụt !)
davidkomer

6
Chà, nếu đối tượng của bạn chỉ đi vòng tròn trong một vòng tròn, thì chắc chắn ... còn khi một chiếc hộp mà người chơi đang đẩy thì sao? Khi bạn gọi getP vị trí (bây giờ + 100), nó có dự đoán tương lai để biết khi nào người chơi sẽ ngừng đẩy nó không? Khi bạn gọi getP vị trí (bây giờ-1000), nó có phải nhớ quá khứ không?
dùng253751

Câu trả lời:


34

... Hoạt động bên trong của hàm đó được tạo thông qua công thức toán học thích hợp ...

Điều này sẽ làm việc cho một số loại vấn đề nhất định và cụm từ chính để tìm kiếm là một giải pháp dạng đóng . Ví dụ, trong Chương trình không gian Kerbal, chuyển động của tàu vũ trụ trên quỹ đạo được tính theo cách này. Thật không may, hầu hết các vấn đề không tầm thường (ví dụ như sự tái lập khí quyển của tàu vũ trụ đã nói) không có giải pháp dạng đóng được biết đến. Do đó, nhu cầu về các xấp xỉ số đơn giản hơn về mặt toán học (tức là integrate()theo thời gian).


À ... tuyệt vời! Nếu bạn có một phút - bạn nghĩ gì khi nhắm đến phương pháp chức năng này, và sau đó sẽ tích lũy lại nếu tôi không thể tìm ra cách làm cho nó hoạt động (ví dụ: nếu tôi đang xử lý một vấn đề hình thức không đóng hoặc Tôi không thể tìm ra cách biến nó thành một)? Tôi thích ý tưởng tạo các hàm vì nó phù hợp với toán học 1: 1 - nhưng nếu tôi luôn luôn chắc chắn rơi vào ngõ cụt thì có lẽ nó không đáng ...
davidkomer

8
@davidkomer Tại sao bạn thậm chí muốn tiếp tục tạo các hàm? Nếu bạn có thể kéo cái này ra, thì bạn chỉ cần tính toán trước và ghi lại toàn bộ quỹ đạo! Tất nhiên, mọi người đã làm điều này: nó được gọi là hoạt hình và nó có phần tinh tế.
Joker_vD

Các chức năng thay đổi dựa trên động lực thời gian chạy ... xem ví dụ về bóng nảy FRP
davidkomer

Trên thực tế tôi sẽ cần cập nhật ví dụ đó giống như pong, với các đối tượng chuyển động được điều khiển ngẫu nhiên / bởi người dùng ...
davidkomer

10

Vấn đề với cách tiếp cận của bạn là, bạn không có lịch sử về đối tượng của mình. Bạn có thể tính toán vị trí nếu bạn di chuyển theo một hướng, nhưng điều gì xảy ra nếu bạn nhấn một cái gì đó và bật lại?
Nếu bạn tích lũy từ vị trí được biết đến cuối cùng của mình, bạn có thể xử lý tác động và tiếp tục từ đó. Nếu bạn cố gắng tính toán nó từ đầu, bạn phải tính toán lại tác động mỗi lần, hoặc đặt nó làm vị trí bắt đầu mới.

Ví dụ của bạn làm tôi nhớ đến một trò chơi đua xe. (Tôi không biết vị trí sẽ được điều khiển bởi động cơ vật lý, nhưng tôi nghĩ nó hoạt động rất tốt để giải thích)
Nếu bạn lái xe với chiếc xe của mình, bạn có thể tăng tốc và giảm tốc độ. Bạn không thể tính toán vị trí của mình mà không biết cấu hình tốc độ của chiếc xe của bạn trông như thế nào từ đầu đến giờ. Tích lũy khoảng cách dễ dàng hơn nhiều so với việc lưu trữ tốc độ bạn có trong mọi khung hình từ đầu đến giờ.

Disclaimer: Bây giờ tôi chưa viết vật lý trò chơi, đó chỉ là cách tôi nhìn nhận vấn đề.

Chỉnh sửa:
Trong sơ đồ này, bạn có thể thấy các giá trị thay đổi theo thời gian.
red = tăng tốc (từ bắt đầu tăng tốc đến sloving xuống)
green = speed (từ bắt đầu đến dừng)
blue = con đường bạn đã đi.

Tổng tốc độ là tích phân của gia tốc từ điểm bắt đầu đến nhật ký thực tế của bạn. (Vùng giữa đường và trục)
Cách là tích phân tốc độ của bạn.
Nếu bạn biết các giá trị cho gia tốc của mình, bạn có thể tính các giá trị khác. Nhưng nếu tôi không nhầm thì tích phân cũng được tính bằng tích lũy trên PC. Và đó là cách chi phí cao hơn để lưu trữ tất cả các giá trị gia tốc.
Thêm vào đó, có lẽ quá nhiều để tính mọi khung hình.

biểu đồ gia tốc / tốc độ / cách thời gian

Tôi biết, kỹ năng vẽ của tôi là tuyệt vời. ;)

Chỉnh sửa 2:
Ví dụ này là cho chuyển động tuyến tính. Hướng Canging làm cho điều này thậm chí còn khó khăn hơn.


"hoặc đặt nó làm vị trí bắt đầu mới." - vâng, nhưng tôi không thấy vấn đề với điều đó :) Re: ví dụ về xe hơi ... Tôi đang có cảm giác mạnh mẽ rằng tôi thực sự cần phải bắt đầu chơi với một thứ phức tạp hơn như thế để hiểu được điều này thất bại .. .
davidkomer

thiết lập một vị trí mới có lẽ không phải là một vấn đề. tôi đã chỉnh sửa phần xe
Linaith

1
Trong một trò chơi xe hơi, tôi tưởng tượng việc tăng tốc sẽ còn phức tạp hơn nữa. Có lẽ sẽ có những cú nhảy và gai, và nó có thể phụ thuộc vào tốc độ. (Ví dụ: khả năng tăng tốc giảm xuống 0 khi xe đạt tốc độ tối đa.)
jpmc26

3
@davidkomer thậm chí không bận tâm đến một chiếc xe hơi (trừ khi bạn muốn), một nền tảng cơ bản sẽ làm. Làm thế nào để mario.getPocation (Thời gian) hoạt động trong Super Mario Bros?
dùng253751

8

Tuy nhiên, tôi không hiểu tại sao nó lại tích lũy như thế này khi nó có thể dễ dàng nhận được bằng cách thay đổi một chức năng. Ví dụ: getPocation = makeNewFunction () có thể trả về một cái gì đó có chữ ký của Thời gian -> Vị trí và hoạt động bên trong của hàm đó được tạo thông qua công thức toán học thích hợp.

Bạn có thể!

Nó được gọi là sử dụng một phân tích hoặc giải pháp dạng đóng . Nó có lợi ích là chính xác hơn, vì các lỗi làm tròn tích lũy theo thời gian là không tồn tại.

Tuy nhiên, điều này hoạt động nếu và chỉ khi bạn biết một hình thức đóng như vậy trước. Đối với các trò chơi, điều này khá thường xuyên không phải là trường hợp.

Chuyển động của người chơi là thất thường và đơn giản là không thể đưa vào một số chức năng được tính toán trước. Người chơi có thể và sẽ thay đổi vận tốc và định hướng của mình khá thường xuyên.

Các NPC có khả năng sử dụng các giải pháp dạng đóng, và trên thực tế đôi khi họ làm như vậy. Điều này có một số nhược điểm khác, tuy nhiên. Hãy nghĩ về một trò chơi đua xe đơn giản. Mỗi khi xe của bạn va chạm với xe khác, bạn phải thay đổi chức năng của mình. Có lẽ chiếc xe di chuyển nhanh hơn tùy thuộc vào lòng đất. Sau đó, việc tìm kiếm một giải pháp dạng đóng như vậy sẽ khá khó khăn. Trong thực tế, có nhiều trường hợp tìm thấy một hình thức đóng như vậy là không thể hoặc phức tạp đến mức đơn giản là không khả thi.

Một ví dụ tuyệt vời về việc sử dụng giải pháp dạng đóng là Chương trình Không gian Kerbal. Ngay khi tên lửa của bạn đi vào quỹ đạo và không bị đẩy, KSP có thể đặt nó "trên đường ray". Các quỹ đạo được xác định trước trong hệ thống hai cơ thể và là định kỳ. Miễn là tên lửa không áp dụng thêm lực đẩy nữa, bạn đã biết tên lửa sẽ ở đâu và bạn chỉ cần gọigetPositionAtTime(t) (tên của nó không được đặt tên chính xác, nhưng bạn hiểu ý).

Tuy nhiên, trên thực tế, chỉ cần sử dụng tích hợp từng bước thường sẽ thực tế hơn nhiều. Nhưng khi bạn thấy một tình huống mà một giải pháp dạng đóng tồn tại và dễ tính toán, hãy tìm nó! Không có lý do để không sử dụng nó.

Ví dụ: nếu nhân vật của bạn đang nhắm một khẩu pháo, bạn có thể dễ dàng hiển thị điểm tác động dự đoán của quả đạn pháo bằng cách sử dụng giải pháp dạng đóng. Và, nếu trò chơi của bạn không cho phép thay đổi quá trình của quả đạn pháo (chẳng hạn như không có gió), bạn thậm chí có thể sử dụng nó để di chuyển quả đạn pháo. Lưu ý rằng bạn cần phải chăm sóc đặc biệt các chướng ngại vật di chuyển vào đường đi của quả đạn pháo của bạn.

Có rất nhiều tình huống tương tự. Nếu bạn đang xây dựng một trò chơi dựa trên vòng, thì có khả năng sẽ có nhiều giải pháp dạng đóng hơn khi xây dựng trò chơi RTS, vì bạn biết trước tất cả các thông số và có thể nói chắc chắn rằng chúng không thay đổi (không có gì thay đổi đột ngột vào con đường đó chẳng hạn).

Lưu ý rằng có các kỹ thuật để chống lại sự thiếu chính xác về số của tích hợp bước. Ví dụ: bạn có thể theo dõi lỗi tích lũy và áp dụng thuật ngữ khắc phục để kiểm tra lỗi, ví dụ: Kahan Summation


8

Trong trường hợp chỉ là một quả bóng nảy đơn giản, đến với các giải pháp dạng đóng là dễ dàng. Tuy nhiên, các hệ thống phức tạp hơn có xu hướng yêu cầu giải phương trình vi phân thông thường (ODE). Người giải quyết số được yêu cầu để xử lý tất cả các trường hợp đơn giản nhất.

Thực tế, có hai lớp bộ giải ODE số: rõ ràng và ẩn. Người giải quyết rõ ràng cung cấp một xấp xỉ dạng đóng cho trạng thái tiếp theo của bạn, trong khi người giải quyết ẩn yêu cầu giải phương trình để làm như vậy. Những gì bạn mô tả cho quả bóng nảy của bạn thực sự là một bộ giải ODE ngầm, cho dù bạn có biết hay không!

Người giải quyết ngầm có lợi thế là có thể sử dụng các bước thời gian lớn hơn nhiều. Đối với thuật toán bóng nảy của bạn, dấu thời gian của bạn có thể lớn nhất bằng thời lượng cho đến lần va chạm tiếp theo (sẽ thay đổi chức năng của bạn). Điều này có thể làm cho chương trình của bạn chạy nhanh hơn nhiều. Tuy nhiên, nói chung, chúng ta không thể luôn tìm thấy các giải pháp ngầm tốt cho ODE mà chúng ta quan tâm. Khi chúng ta không thể, chúng ta rơi vào sự tích hợp rõ ràng.

Lợi thế lớn mà tôi thấy với sự tích hợp rõ ràng là các vấn đề nổi tiếng. Bạn có thể mở bất kỳ sách giáo khoa nào từ thập niên 60 và đọc tất cả những gì bạn cần biết về những điều kỳ quặc phát sinh với các kỹ thuật tích hợp cụ thể. Do đó, một nhà phát triển học các kỹ năng này một lần và họ không bao giờ phải học lại chúng. Nếu bạn đang thực hiện tích hợp ngầm, mỗi trường hợp sử dụng hơi khác nhau, với các vấn đề khác nhau. Khó hơn một chút để áp dụng những gì bạn học được từ một nhiệm vụ vào nhiệm vụ tiếp theo.


1

pos (t) = v (t) * t

chỉ hoạt động nếu pos (0) = 0 và v (t) = k

bạn không thể liên kết vị trí với thời gian mà không có kiến ​​thức về điều kiện ban đầu và toàn bộ hàm vận tốc, vì vậy phương trình là một xấp xỉ của tích phân

pos (t) = tích phân của v (t) dt từ 0 đến t

BIÊN TẬP _________

Đây là một bằng chứng nhỏ cho mỗi bình luận (giả sử pos (0) = 0)

cho v (t) = 4

eqn 1: pos (t) = 4 * t (đúng)

eqn 2: pos (t) = c + 4 * t từ 0 đến t = 4 * t (đúng)

hãy để v (t) = 2 * t

eqn 1: pos (t) = 2 * t ^ 2 (sai)

eqn 2: pos (t) = c + t ^ 2 từ 0 đến t = t ^ 2 (đúng)

Tôi nên thêm rằng phương trình của bạn đã có các yếu tố tăng tốc không đổi (tức là phương trình của bạn là eqn 2 trong đó v (t) = v0 + a * t và các giới hạn tích hợp là t0 và t), vì vậy phương trình của bạn sẽ hoạt động miễn là bạn cập nhật vị trí ban đầu, vận tốc ban đầu và gia tốc không đổi.

EDIT2 ________

Tôi cũng nên thêm rằng bạn cũng có thể tính toán vị trí với vị trí ban đầu, vận tốc ban đầu, gia tốc ban đầu và độ giật liên tục. Nói cách khác, bạn có thể tạo một hàm dựa trên eqn 2 đại diện cho vị trí và thời gian bằng cách tách nó thành các dẫn xuất của nó, ví dụ như vận tốc, giật, bất cứ điều gì tiếp theo, v.v., v.v., nhưng bạn sẽ chỉ chính xác trong phương trình của mình nếu v (t) có thể được mô hình hóa theo cách đó. Nếu v (t) không thể được mô hình hóa chỉ với vận tốc, gia tốc, giật liên tục, v.v., thì bạn cần quay lại với một xấp xỉ của eqn 2, điều này có xu hướng xảy ra khi bạn có những thứ nảy, sức cản không khí, gió, v.v. .


một hằng số. nó chỉ có nghĩa là v (t) không được thay đổi theo thời gian
Kyy13

Tôi sẽ phải ngồi với điều này và tìm hiểu tại sao nó đúng ... nâng cao ngay bây giờ :) Tôi đã đăng một mẫu mã trong câu hỏi trong trường hợp thay đổi mọi thứ
davidkomer

không có vấn đề gì, được cập nhật lại với những từ tốt hơn :)
Kyy13
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.