Simulação física de um pêndulo duplo, treinamento de uma rede neural para aproximar suas acelerações angulares e refinamento do modelo com dados físicos simulados próximos ao regime de interesse.
Na animação, a solução das equações físicas aparece em azul, o modelo original em laranja e o modelo refinado em verde. O gráfico à direita acompanha o erro instantâneo da segunda massa ao longo de dez segundos.
A pergunta que motivou este trabalho foi: uma rede neural consegue aprender a dinâmica local de um sistema caótico e continuar útil quando suas previsões são integradas por vários segundos?
O pêndulo duplo é um bom teste para essa ideia. As equações de movimento são conhecidas, mas pequenas diferenças no estado ou na aceleração crescem durante uma previsão livre. Por isso, acertar a aceleração em pontos isolados não garante uma trajetória correta no longo prazo.
O experimento compara três sistemas:
- Equações físicas: referência numérica integrada com DOP853 e tolerâncias estritas.
- ML antes do refinamento: uma MLP treinada em trajetórias distribuídas por uma região ampla do espaço de estados.
- ML refinado: uma cópia do modelo original treinada por mais algumas épocas com observações próximas da condição inicial avaliada.
Os dados chamados de "observados" continuam sendo sintéticos. Eles vêm da simulação física de alta precisão e recebem ruído gaussiano para representar erro de medição. Não há dados de sensores ou de um pêndulo real neste repositório.
O refinamento utilizou 12 trajetórias locais de 6 segundos, totalizando 72 segundos simulados e 1.812 observações. Na execução documentada, os resultados foram:
| Métrica | Antes | Depois | Variação |
|---|---|---|---|
| RMSE de |
0,7761 rad/s² | 0,7210 rad/s² | melhora de 7,1% |
| RMSE de |
1,0958 rad/s² | 0,9615 rad/s² | melhora de 12,3% |
| RMSE de posição | 1,2374 m | 0,8934 m | melhora de 27,8% |
| Horizonte até erro de 0,25 m | 2,840 s | 2,740 s | piora de 0,100 s |
| Máxima deriva relativa de energia | 235,212% | 94,638% | melhora de 59,8% |
O resultado não é uma melhora uniforme. O modelo refinado reduziu os erros médios e a deriva de energia, mas cruzou o limiar de 0,25 m um pouco antes. O horizonte mede o primeiro cruzamento; o RMSE resume toda a trajetória. Em um sistema caótico, essas duas leituras podem se mover em direções diferentes.
Os números acima correspondem a uma semente e a uma condição inicial principal. Eles descrevem esta execução, não uma garantia de desempenho para todo o espaço de estados.
O primeiro painel compara a solução física com a previsão livre da rede antes do refinamento. Ele reúne ângulos, trajetória cartesiana, erro de posição e deriva relativa de energia.
O segundo painel coloca os três sistemas na mesma escala: referência física, baseline e modelo refinado com 72 segundos de observações simuladas.
A animação completa do pós-treinamento permanece no início do README. As demais
visualizações também estão disponíveis em notebooks/images.
flowchart LR
A["Equações físicas"] --> B["Trajetórias sintéticas"]
B --> C["Estados com ruído"]
C --> D["Características periódicas"]
D --> E["MLP baseline"]
E --> F["Rollout livre com RK4"]
A --> G["Observações físicas locais"]
G --> H["Refinamento da MLP"]
H --> I["Novo rollout com RK4"]
A --> J["Métricas de referência"]
F --> J
I --> J
O estado usado pelo integrador é
com os ângulos medidos a partir da vertical orientada para baixo. As posições cartesianas são
Essa transformação é usada nas animações e no cálculo do erro em metros.
As acelerações
A trajetória de referência usa scipy.integrate.solve_ivp com o método DOP853,
rtol=1e-10 e atol=1e-12.
O conjunto de base usa, por padrão, 120 trajetórias de 5 segundos com passo de 0,04 s. As condições iniciais são sorteadas em uma região ampla:
-
$\theta_1,\theta_2 \sim \mathcal{U}(-\pi,\pi)$ ; -
$\omega_1,\omega_2 \sim \mathcal{U}(-2,2)$ rad/s.
As entradas recebem ruído gaussiano com desvios padrão de 0,01 rad nos ângulos e 0,03 rad/s nas velocidades. Os alvos continuam sendo as acelerações exatas da simulação.
A separação entre treino e teste é feita por trajetória, usando
GroupShuffleSplit. Assim, pontos temporais da mesma trajetória não aparecem
dos dois lados da avaliação.
Os ângulos não entram diretamente na rede. Cada estado é transformado em 11 características:
Essa representação respeita a periodicidade dos ângulos. O modelo usa:
MLPRegressordo scikit-learn;- duas camadas ocultas de 96 neurônios;
- ativação
tanh; - otimizador Adam;
- padronização independente das entradas e dos alvos;
- parada antecipada no treinamento de base;
- semente padrão igual a 42.
A rede prevê apenas
O segundo estágio preserva o baseline e treina uma cópia. As trajetórias adicionais começam perto da condição inicial de avaliação, com perturbações de 18 graus nos ângulos e 0,35 rad/s nas velocidades.
Os escaladores do baseline são mantidos. A cópia recebe 50 épocas adicionais,
taxa de aprendizado de
O projeto mede:
- MAE, RMSE e
$R^2$ das acelerações em trajetórias reservadas; - RMSE angular, usando diferença principal no intervalo
$[-\pi,\pi]$ ; - RMSE da posição da segunda massa;
- primeiro instante em que o erro de posição supera 0,25 m;
- máxima deriva relativa de energia durante o rollout.
double-pendulum-python/
├── double_pendulum.py
├── pendulo_duplo_dados_observados.csv
├── pendulo_duplo_ml_animacao.gif
├── pendulo_duplo_ml_refinamento.gif
├── pendulo_duplo_ml_resultados.png
├── pendulo_duplo_ml_refinamento_resultados.png
└── notebooks/
├── double_pendulum.ipynb
└── images/
├── pendulo_duplo_ml_animacao.gif
├── pendulo_duplo_ml_refinamento.gif
├── pendulo_duplo_ml_resultados.png
└── pendulo_duplo_ml_refinamento_resultados.png
double_pendulum.py: simulação, treinamento, refinamento, métricas e geração dos artefatos.notebooks/double_pendulum.ipynb: versão didática, com as fórmulas e o código apresentados em sequência.pendulo_duplo_dados_observados.csv: dados usados no refinamento documentado.notebooks/images: cópias versionadas das figuras e animações exibidas pelo notebook e por este README.
Os artefatos da raiz são as saídas padrão do script. As imagens em
notebooks/images/ são snapshots versionados; se o experimento for executado
novamente, elas só mudam quando as novas saídas forem copiadas para essa pasta.
O projeto foi validado com:
| Componente | Versão |
|---|---|
| Python | 3.13.9 |
| NumPy | 2.3.5 |
| SciPy | 1.16.3 |
| Matplotlib | 3.10.6 |
| scikit-learn | 1.7.2 |
| Pillow | 12.0.0 |
Versões recentes dessas bibliotecas também devem funcionar. O notebook requer Jupyter Notebook ou JupyterLab.
O treinamento usa CPU. MLPRegressor não utiliza CUDA, portanto a GPU não é
ocupada por este projeto.
Clone o repositório e entre na pasta:
git clone https://github.com/Everlynmartins/double-pendulum-python.git
cd double-pendulum-pythonCom venv:
python -m venv .venvNo PowerShell:
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install numpy scipy matplotlib scikit-learn pillow jupyterCom Conda:
conda create -n double-pendulum python=3.13 -y
conda activate double-pendulum
python -m pip install numpy scipy matplotlib scikit-learn pillow jupyterpython .\double_pendulum.py --no_showEsse comando treina o baseline, registra os dados observados, refina a cópia do modelo, calcula as métricas e produz os dois painéis e as duas animações GIF.
Para verificar o ambiente sem gerar as animações e com menos dados:
python .\double_pendulum.py `
--train_trajectories 30 `
--train_duration 3 `
--observed_trajectories 6 `
--observed_duration 4 `
--refinement_epochs 30 `
--skip_animation `
--no_showpython .\double_pendulum.py --skip_refinement --no_showjupyter notebook .\notebooks\double_pendulum.ipynbO notebook começa com MODO_RAPIDO = True. Altere para False para usar os
parâmetros completos descritos no relatório científico incorporado a ele.
| Argumento | Padrão | Descrição |
|---|---|---|
--duration |
10.0 |
Duração da comparação principal, em segundos. |
--time_step |
0.02 |
Passo temporal do rollout avaliado. |
--train_trajectories |
120 |
Quantidade de trajetórias do treinamento de base. |
--train_duration |
5.0 |
Duração de cada trajetória de base. |
--train_time_step |
0.04 |
Passo temporal do conjunto de base. |
--angle_noise |
0.01 |
Desvio do ruído angular, em radianos. |
--velocity_noise |
0.03 |
Desvio do ruído de velocidade, em rad/s. |
--seed |
42 |
Semente da geração e do treinamento. |
--observed_trajectories |
12 |
Trajetórias locais usadas no refinamento. |
--observed_duration |
6.0 |
Duração de cada trajetória observada. |
--observed_time_step |
0.04 |
Passo temporal dos dados observados. |
--max_observed_samples |
5000 |
Limite de segurança do conjunto observado. |
--refinement_epochs |
50 |
Épocas adicionais da cópia refinada. |
--refinement_learning_rate |
1e-4 |
Taxa de aprendizado do refinamento. |
--fps |
25 |
Quadros por segundo das animações. |
--skip_animation |
falso | Não gera GIF ou MP4. |
--skip_refinement |
falso | Executa somente o experimento original. |
--no_show |
falso | Não abre janelas gráficas durante a execução. |
Use python double_pendulum.py --help para consultar também os argumentos que
alteram os caminhos de saída.
| Arquivo | Conteúdo |
|---|---|
pendulo_duplo_ml_resultados.png |
Comparação entre a física e o baseline. |
pendulo_duplo_ml_animacao.gif |
Animação da física e do baseline. |
pendulo_duplo_dados_observados.csv |
Estados exatos, estados com ruído e acelerações-alvo. |
pendulo_duplo_ml_refinamento_resultados.png |
Comparação estática antes e depois do refinamento. |
pendulo_duplo_ml_refinamento.gif |
Animação com física, baseline e modelo refinado. |
GIF é o formato padrão porque funciona sem programas externos. A geração de
MP4 requer que o FFmpeg esteja instalado e disponível no PATH:
python .\double_pendulum.py `
--animation_path baseline.mp4 `
--refinement_animation_path refinamento.mp4 `
--no_show- A referência é uma simulação ideal sem atrito, folgas ou massa das hastes.
- As acelerações-alvo são conhecidas exatamente; obtê-las de medições reais seria consideravelmente mais difícil.
- O rollout detalhado usa uma condição inicial principal.
- O refinamento é local e pode melhorar uma região enquanto piora outras.
- A rede não possui uma restrição explícita de conservação de energia.
- Não foi feita uma busca exaustiva de hiperparâmetros.
- Em horizontes longos, erro ponto a ponto deixa de ser a única medida útil para um sistema caótico.
- avaliar várias condições iniciais e sementes com Monte Carlo;
- medir intervalos de confiança para a diferença entre baseline e refinamento;
- aprender apenas o resíduo de um modelo físico aproximado;
- adicionar regularização de energia durante o rollout;
- comparar integradores simpléticos e modelos hamiltonianos;
- substituir os dados simulados por medições de câmera ou encoders.
Desenvolvido por Everlyn Martins.
Este repositório ainda não possui uma licença de uso definida. Até que uma licença seja adicionada, consulte a autora antes de reutilizar ou redistribuir o conteúdo.


