Spaces:
Build error
Build error
File size: 3,114 Bytes
145f794 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import numpy as np
import pandas as pd
from scipy.optimize import minimize
from scipy.interpolate import interp1d
from scipy.optimize import differential_evolution
def objective_function(params, t, pv_hist, cv_hist):
# Unpack parameters
Kp, tau, theta = params
# Basic constraints to keep parameters realistic
if Kp <= 0 or tau <= 0 or theta < 0:
return 1e9 # Return a large number for invalid parameters
# Simulate the model response
pv_sim = simulate_fopdt(params, t, cv_hist)
# Calculate Sum of Squared Errors (SSE)
error = np.sum((pv_hist - pv_sim) ** 2)
return error
def simulate_fopdt(params, t, cv):
Kp, tau, theta = params
dt = t[1] - t[0]
pv_sim = np.zeros_like(t)
# Calculate the number of discrete steps for the dead time
delay_steps = int(round(theta / dt))
# Create a delayed version of the CV signal
cv_delayed = np.zeros_like(cv)
if delay_steps > 0 and delay_steps < len(cv):
cv_delayed[delay_steps:] = cv[:-delay_steps]
else:
cv_delayed = cv
for i in range(1, len(t)):
# First-order dynamics using the pre-calculated delayed CV
d_pv = (Kp * cv_delayed[i] - pv_sim[i - 1]) / tau
pv_sim[i] = pv_sim[i - 1] + d_pv * dt
return pv_sim
def identify_process_model(t, pv, cv):
bounds = [(0.1, 5.0), (1, 20.0), (0.5, 5.0)] # Adjusted bounds for robustness
# Run the optimization using differential_evolution.
result = differential_evolution(
objective_function,
bounds,
args=(t, pv, cv),
popsize=30,
maxiter=1000,
tol=0.01,
recombination=0.7,
strategy="best1bin",
)
if result.success:
identified_params = result.x
return identified_params
else:
print("Error: System identification failed.")
print(result.message)
return None
def calculate_tuning_params(Kp, tau, theta):
if Kp is None or tau is None or theta is None or theta == 0:
print("Cannot calculate tuning rules with invalid model parameters.")
return {}
# --- Ziegler-Nichols ---
zn_kc = (1.2 * tau) / (Kp * theta)
zn_ti = 2.0 * theta
zn_td = 0.5 * theta
zn_kp = zn_kc
zn_ki = zn_kc / zn_ti
zn_kd = zn_kc * zn_td
# --- Cohen-Coon ---
cc_kc = (tau / (Kp * theta)) * (4 / 3 + theta / (4 * tau))
cc_ti = theta * (32 + 6 * theta / tau) / (13 + 8 * theta / tau)
cc_td = theta * 4 / (11 + 2 * theta / tau)
cc_kp = cc_kc
cc_ki = cc_kc / cc_ti
cc_kd = cc_kc * cc_td
# --- IMC (Lambda) Tuning ---
lambda_val = tau
imc_kc = (tau + 0.5 * theta) / (Kp * (lambda_val + 0.5 * theta))
imc_ti = tau + 0.5 * theta
imc_td = (tau * theta) / (2 * tau + theta)
imc_kp = imc_kc
imc_ki = imc_kc / imc_ti
imc_kd = imc_kc * imc_td
tuning_results = {
"Ziegler-Nichols": {"Kp": zn_kp, "Ki": zn_ki, "Kd": zn_kd},
"Cohen-Coon": {"Kp": cc_kp, "Ki": cc_ki, "Kd": cc_kd},
"IMC (Lambda)": {"Kp": imc_kp, "Ki": imc_ki, "Kd": imc_kd},
}
return tuning_results
|