Buckets:
| import streamlit as st | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import pandas as pd | |
| from scipy import linalg | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| import time | |
| def show_pid_control(): | |
| """Interface pour le contrôle PID""" | |
| st.header("🎯 Contrôle PID") | |
| # Explication théorique | |
| with st.expander("📖 Théorie du contrôle PID", expanded=True): | |
| st.markdown(r""" | |
| ### Contrôleur PID | |
| La loi de commande PID est : | |
| $$ | |
| u(t) = K_p e(t) + K_i \int_0^t e(\tau) d\tau + K_d \frac{de(t)}{dt} | |
| $$ | |
| où : | |
| - $e(t)$ : erreur de suivi | |
| - $K_p$ : gain proportionnel | |
| - $K_i$ : gain intégral | |
| - $K_d$ : gain dérivé | |
| ### Effets des gains | |
| - **Kp** : Rapidité de réponse, mais oscillations si trop élevé | |
| - **Ki** : Élimination de l'erreur statique | |
| - **Kd** : Amortissement des oscillations | |
| """) | |
| # Interface pour le contrôle PID | |
| st.subheader("🧪 Simulateur de contrôle PID") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("### Paramètres du système") | |
| system_type = st.selectbox("Type de système", | |
| ["Masse-ressort", "Double intégrateur", "Robot souple"]) | |
| if system_type == "Masse-ressort": | |
| st.info("Système masse-ressort : m=1kg, k=10N/m, c=0.1Ns/m") | |
| elif system_type == "Double intégrateur": | |
| st.info("Double intégrateur : position et vitesse") | |
| elif system_type == "Robot souple": | |
| st.info("Robot souple : poutre en flexion") | |
| with col2: | |
| st.markdown("### Gains PID") | |
| Kp = st.slider("Kp (Proportionnel)", 0.1, 100.0, 5.0, 0.1) | |
| Ki = st.slider("Ki (Intégral)", 0.0, 50.0, 1.0, 0.1) | |
| Kd = st.slider("Kd (Dérivé)", 0.0, 10.0, 0.1, 0.01) | |
| reference = st.slider("Consigne", -5.0, 5.0, 1.0, 0.1) | |
| if st.button("🎯 Lancer le contrôle PID", type="primary"): | |
| simulate_pid_control(system_type, Kp, Ki, Kd, reference) | |
| def simulate_pid_control(system_type, Kp, Ki, Kd, reference): | |
| """Simule le contrôle PID""" | |
| dt = 0.01 | |
| n_steps = 1000 | |
| t = np.linspace(0, (n_steps-1)*dt, n_steps) | |
| # Système simulé | |
| if system_type == "Masse-ressort": | |
| A = np.array([[0, 1], [-10, -0.1]]) | |
| B = np.array([[0], [1]]) | |
| C = np.array([[1, 0]]) | |
| elif system_type == "Double intégrateur": | |
| A = np.array([[0, 1], [0, 0]]) | |
| B = np.array([[0], [1]]) | |
| C = np.array([[1, 0]]) | |
| else: | |
| # Robot souple simplifié | |
| A = np.array([[0, 1], [-1, -0.1]]) | |
| B = np.array([[0], [1]]) | |
| C = np.array([[1, 0]]) | |
| # Simulation PID | |
| x = np.zeros((2, n_steps)) | |
| u = np.zeros(n_steps) | |
| error = np.zeros(n_steps) | |
| integral = 0 | |
| prev_error = 0 | |
| for i in range(1, n_steps): | |
| # Erreur | |
| error[i] = (reference - C @ x[:, i-1])[0] | |
| # PID | |
| integral += error[i] * dt | |
| derivative = (error[i] - prev_error) / dt | |
| u[i] = Kp * error[i] + Ki * integral + Kd * derivative | |
| # Évolution du système | |
| x_dot = A @ x[:, i-1] + B.flatten() * u[i] | |
| x[:, i] = x[:, i-1] + x_dot * dt | |
| prev_error = error[i] | |
| # Visualisation | |
| fig = make_subplots(rows=2, cols=1, | |
| subplot_titles=("Réponse du système", "Commande PID"), | |
| vertical_spacing=0.15) | |
| # Réponse | |
| fig.add_trace(go.Scatter(x=t, y=x[0, :], name='Sortie', | |
| line=dict(color='blue')), | |
| row=1, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=np.ones_like(t) * reference, name='Consigne', | |
| line=dict(color='red', dash='dash')), | |
| row=1, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=error, name='Erreur', | |
| line=dict(color='green')), | |
| row=1, col=1) | |
| # Commande | |
| fig.add_trace(go.Scatter(x=t, y=u, name='Commande u(t)', | |
| line=dict(color='purple')), | |
| row=2, col=1) | |
| fig.update_layout(height=600, showlegend=True) | |
| st.plotly_chart(fig, use_container_width=True) | |
| # Métriques | |
| steady_state_error = np.abs(error[-100:]).mean() | |
| overshoot = (np.max(x[0, :]) - reference) / reference * 100 if reference != 0 else 0 | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| st.metric("Erreur statique", f"{steady_state_error:.4f}") | |
| with col2: | |
| st.metric("Dépassement (%)", f"{overshoot:.1f}%") | |
| with col3: | |
| settling_time = np.where(np.abs(error) < 0.05 * np.abs(reference))[0] | |
| settling_time = settling_time[0] * dt if len(settling_time) > 0 else n_steps * dt | |
| st.metric("Temps de réponse", f"{settling_time:.2f} s") |
Xet Storage Details
- Size:
- 5.04 kB
- Xet hash:
- 35e396ae65c3a769b779c4bf0116bbe517d6d0cb5dd8ab19104203f583fd7f58
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.