É possível fazer simulação realística de sistemas solares em n-corpos em tamanho e massa?

Nota importante: esta questão não tem qualquer relação com o “PhysX”, que é um sistema de física de jogos de computador (útil para a física em jogos de arcade, como jogos de bola, etc); O PhysX é um sistema integrado ao Unity3D e a outros mecanismos de jogos; PhysX é totalmente irrelevante aqui.

//////////////////// UPDATE (leia primeiro o fundo) /////////////////////

Tenho registrado os valores e pesquisando onde está o problema exato, e acho que o encontrei. Eu tenho algo parecido com isso no meu código

Velocity += Acceleration * Time.deltaTime; position += Velocity * Time.deltaTime; 

A aceleração é algo como 0,0000000000000009 .. agora. À medida que o código flui, a velocidade aumenta como deveria, sem problemas com o flutuador. Mas no início, a posição inicial da Terra é (0,0,23500f). Você pode ver isso no gráfico que eu dei no final.

Bem, agora, quando eu adiciono velocidade * timedelta (que é algo como 0,00000000000000005 neste ponto) para a posição que é 23500, basicamente não adiciona. posição ainda é (0, 0, 23500) não algo como (0,0, 23500,00000000000005), assim, a terra não se move, assim, a aceleração não muda.

Se eu definir a posição inicial da terra para 0,0,0 e ainda, defina a aceleração para 0,0000000000000000009 para supor que a posição é (0,0,23500) Então, “ADDS” a velocidade * timedelta. Torna-se algo como (0,0,000000000000000000005) e mantém aumentos. Quando o float é 0, não há problema em adicionar um valor tão pequeno. Mas se o float é algo como 23500, então ele não adiciona os valores pequenos.

Eu não sei se é exatamente o problema da unidade ou o float do c #.

E é por isso que não consigo trabalhar com valores pequenos. Se eu puder superar isso, meu problema será resolvido.

////////////////////////////////////////////////// /////////////////////////////

Eu tenho desenvolvido Phyics no corpo para simular o nosso sistema solar, então eu tenho coletado dados para torná-lo o mais realista possível. Mas há um problema com o tamanho dos dados. Eu procurei cada minúsculo pedaço de internet e não consegui encontrar uma única explicação de como as pessoas superam isso. (Se assim for) Então eu estou tentando o meu tiro aqui.

Então, para manter a relação entre distância, raio e “massa” entre planetas fixos, eu criei um arquivo excel para calcular todos os dados. (Porque por que diabos alguém colocaria “qual seria a massa da Terra se tivesse” aquele “gráfico de raio” na internet?) Eu darei o ss como anexo. Basicamente, “normaliza” ou, em outras palavras, “escala” todas as propriedades de um planeta para uma dada referência. Neste caso, tomei a referência como “raio da terra”.

Eu trabalho em união, e você sabe, você não pode trabalhar com valores “grandes demais” ou “pequenos demais” em unidade. Então eu tive que escalar o sistema solar, “muito!”

Então eu uso a lei de gravitação universal de Newton, que é F = GMm / r ^ 2, para simplificar, eu estou calculando diretamente a = GM / r ^ 2, para um dado corpo de todos os outros corpos.

Assim, o valor real da aceleração gravitacional da Terra “em direção ao sol” é de aproximadamente 0,000006 km / s ^ 2, o que é um valor incrivelmente pequeno para se trabalhar em unidade, mas poderia funcionar. No entanto, para obter este valor, eu preciso definir o raio da Terra (escala) para 6371 unidade, e o Sol para a escala de 696,342 !, que é muito grande para torná-lo na unidade.

Então eu disse, deixe o raio da Terra ser 1, em unidades de unidade. Então, quando o raio muda, tudo muda, a massa, a distância … guardei a densidade do planeta e calculei a massa a partir do novo volume com o novo raio. Todos os cálculos estão no anexo.

Então a coisa é, quando eu tomo o raio da Terra como 1, a aceleração gravitacional em direção ao sol se torna algo como 0,0000000000009 que é ridiculamente pequena. E, claro, o Unity não trabalha com esse valor.

Então, se eu aumentar o raio da Terra, então a massa e o raio do Sol ficam ridiculamente grandes e, novamente, eu não posso trabalhar com isso.

Eu não sei como outras pessoas corrigiram isso, o que eles fizeram para superar esse problema, mas como eu vejo a partir daqui, parece impossível fazer simulação n-body realista do sistema solar. (na unidade pelo menos)

Então eu preciso ter 10 rep para postar imagens -_-, vou dar link em seu lugar. http://berkaydursun.com/solar_system_simulator/data.PNG Também um diretório para cima é a simulação experimental do sistema solar em funcionamento com cálculos de n-corpos, mas com valores UNREALISTIC. Ele funciona muito bem, e até parece de alguma forma próximo do real, mas não, ele não tem as proporções certas ^^ Você pode testá-lo aqui se desejar http://berkaydursun.com/solar_system_simulator/

Edit: WoW eu quase comecei cada parágrafo com “So” ^^

Eu fiz programa sim simulação do sistema também, então aqui estão meus insights:

  1. Renderização

    Eu uso o OpenGL com escala 1: 1 . Todas as unidades estão em SI, por isso [m, s, kg, …] . O problema é iniciado com o Z-buffer . O bit comum do buffer Z é de 16/24/32 bit que não é nem de perto o que você precisa. Eu estou renderizando de 0.1m até 1000 AU então como superar isso?

    Eu consegui gerenciá-lo renderizando com 3 frustrums de uma vez combinando Z- buffering e Z-buffering (o Z-sort é necessário por causa de anéis transparentes … e outros efeitos). Então, primeiro eu faço as partes mais distantes até zfar=1000AU . A cúpula do céu é projetada em z=750AU distância, em seguida, limpa o Z-buffer e renderiza objects até zfar=0.1AU . Em seguida, limpe o Z-buffer novamente e renderize objects próximos a zfar=100000 m .

    Para obter este trabalho, você precisa ter uma matriz de projeção tão precisa quanto possível. A gluPerspective tem cotangens não- gluPerspective , por isso precisa reparar os elementos em questão (leve-me muito tempo para identificar isso). Z near valor Z near depende da largura do bit do buffer Z. Quando codificado corretamente, isso funciona bem, mesmo com zoom 10000x . Eu uso este programa como navegação / pesquisador de objects para o meu telescópio 🙂 em tempo real a partir da minha visão de casa. Eu combino estrelas 3D, corpos de astrais, navios, terra real (via DTM e textura de satélite). É capaz até mesmo de saída anaglyph red-cyan :). Pode render da superfície, atmosfera, espaço … (não apenas trancado na Terra). Nenhuma outra biblioteca de terceiros é usada. Aqui está como parece:

    imgimgimgimgimg

    Como você pode ver funciona bem em qualquer altitude ou zoom a atmosfera é feita como esta atmosfera shader dispersão

  2. simulação

    Eu não estou usando simulação de gravidade n-body porque para isso você precisa de muitos dados que são muito difíceis de obter (e quase impossíveis na precisão desejada). Os cálculos devem ser feitos com muita precisão .

    Eu uso a equação de Kepler, então veja estas:

    • Resolvendo a equação de Kepler
    • Implementação de C ++ .

    Se você ainda quiser usar o modelo de gravidade, use os horizontes do JPL da NASA . Eu acho que eles também têm códigos-fonte em C / C ++, mas eles estão usando um quadro de referência incompatível com os meus mapas, então é inutilizável para mim.

    Em geral, a equação de Kepler tem um erro maior, mas não aumenta com o tempo demais. O modelo de gravidade é mais preciso, mas seu erro está aumentando com o tempo e você precisa atualizar os dados do corpo do astro continuamente para que ele funcione …

[edit1] precisão de integração

sua implementação atual é assim:

 // object variables double acc[3],vel[3],pos[3]; // timer iteration double dt=timer.interval; for (int i=0;i<3;i++) { vel[i]+=acc[i]*dt; pos[i]+=vel[i]*dt; } 

O problema é quando você está adicionando valor muito pequeno e muito grande, então eles são deslocados para o mesmo expoente antes da adição, o que arredondará os dados significativos. Para evitar isso, basta mudá-lo para isto:

 // object variables double vel0[3],pos0[3]; // low double vel1[3],pos1[3]; // high double acc [3],vel [3],pos [3]; // full // timer iteration double dt =timer.interval; double max=10.0; // precision range constant for (int i=0;i<3;i++) { vel0[i]+=acc[i]*dt; if (fabs(vel0[i]>=max)) { vel1[i]+=vel0[i]; vel0[i]=0.0; } vel[i]=vel0[i]+vel1[i]; pos0[i]+=vel[i]*dt; if (fabs(pos0[i]>=max)) { pos1[i]+=pos0[i]; pos0[i]=0.0; } pos[i]=pos0[i]+pos1[i]; } 

Agora o xxx0 está integrado no max e a coisa toda é adicionada ao xxx1

O arredondamento ainda está lá, mas não é mais cumulativo. Você tem que selecionar o valor max que a integração em si é segura e também a adição xxx0+xxx1 tem que ser segura. Então, se os números são muito diferentes para uma divisão, então divida duas vezes ou mais ...

  • como: xxx0+=yyy*dt; if (fabs(xxx0>max0))... if (fabs(xxx1>max1))... xxx0+=yyy*dt; if (fabs(xxx0>max0))... if (fabs(xxx1>max1))...

[Edit2] Estrelas

  • As colors das estrelas A melhor visualização das estrelas que já vi
  • Índice de colors da Star BV para cor RGB aparente todos os catálogos de estrelas usam o índice BV
  • Usando catálogos Scanvasr também link de referência cruzada de nomes de estrelas está lá
  • Skybox: combine diferentes dados em estrela

[Edit3] Melhorando ainda mais a precisão da integração de Newton d'Lambert

O problema básico com a integração iterativa é que a aceleração baseada na gravidade baseada na posição atual do corpo resultará em órbitas maiores, porque durante a etapa de integração a posição muda um pouco que não é considerado na integração ingênua. Para remediar isso, dê uma olhada nesta foto:

integração

Vamos supor que nosso corpo está na órbita circular e na posição de 0 graus. Em vez de usar a direção de aceleração com base na posição atual, usei a posição após 0.5*dt . Isso aumenta a aceleração, resultando em uma precisão muito maior (correspondendo às órbitas do Kepler). Com esse ajuste eu consegui converter com sucesso da órbita de Kepler em Newton d'Lambert para o sistema de 2 corpos. (Fazer isso por n-corpo é o próximo passo). De correlação grosseira com dados reais do nosso sistema solar só é possível para o sistema de 2 corpos não afetados por efeitos de maré e / ou luas. Para construir os próprios dados fictícios, você pode usar a órbita circular de Kepler e a força contripedal que equaliza a gravidade:

 G = 6.67384e-11; v = sqrt(G*M/a); // orbital speed T = sqrt((4.0*M_PI*M_PI*a*a*a)/(G*(m+M))); // orbital period 

onde a é a órbita circular raio m é massa corporal, M é massa corporal focal (sol). Para manter a precisão em tolerância aceitável (para mim) a etapa de integração dt deve ser:

 dt = 0.000001*T 

Então, para colocar um novo corpo para testes basta colocá-lo em:

 pos = (a,0,0) vel = (0,sqrt(G*M/a),0) 

Enquanto o corpo principal principal (Sol) está em:

 pos = (0,0,0) vel = (0,0,0) 

Isso colocará seu corpo em órbita circular para que você possa comparar Kepler versus Newton d'Lambert para avaliar a precisão de sua simulação.

Escalar as coisas não ajudará necessariamente, como você descobriu. Aqui está uma boa leitura sobre coisas a serem consideradas ao usar números de ponto flutuante: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Basicamente fazer uma simulação a partir dos primeiros princípios (leis de Newton) é ruim para precisão numérica, porque você não impregna os methods numéricos com uma idéia da escala de efeitos importantes, então você acaba lançando um monte de efeitos diferentes em diferentes escalas. juntos e o resultado é baixa precisão.

Geralmente, coisas como efemérides para planetas, satélites, etc. não começam com a lei de Newton. Elas começam assumindo que as órbitas são keplerianas, e então pequenas correções perturbativas.

Aqui está um algoritmo que calcula a posição dos planetas (semi-imperial). http://ssd.jpl.nasa.gov/txt/aprx_pos_planets.pdf

Se você quiser fazer uma simulação de N-body, parece que precisará de mais precisão. Se a unidade impedir que você use precisão dupla, sugiro fazer os cálculos em C # simples e convertê-la em precisão única quando o trabalho estiver concluído.