def generate_symbolic_model(T, U, tt, F, simplify=True, constraints=None, dissipation_function=0, **kwargs): """ T: kinetic energy U: potential energy tt: sequence of independent deflection variables ("theta") F: external forces simplify: determines whether the equations of motion should be simplified (default=True) constraints: None (default) or sequence of constraints (will introduce lagrange multipliers) dissipation_function: Rayleigh dissipation function. Its Differential w.r.t. tthetadot is added to the systems equation kwargs: optional assumptions like 'real=True' :returns SymbolicModel instance mod. The equations are contained in mod.eqns """ n = len(tt) for theta_i in tt: assert isinstance(theta_i, sp.Symbol) if constraints is None: constraints_flag = False # ensure well define calculations (jacobian of empty matrix would not be possible) constraints = [0] else: constraints_flag = True assert len(constraints) > 0 constraints = sp.Matrix(constraints) assert constraints.shape[1] == 1 nC = constraints.shape[0] jac_constraints = constraints.jacobian(tt) dissipation_function = sp.sympify(dissipation_function) assert isinstance(dissipation_function, sp.Expr) llmd = st.symb_vector("lambda_1:{}".format(nC + 1)) F = sp.Matrix(F) if F.shape[0] == 1: # convert to column vector F = F.T if not F.shape == (n, 1): msg = "Vector of external forces has the wrong length. Should be " + \ str(n) + " but is %i!" % F.shape[0] raise ValueError(msg) # introducing symbols for the derivatives tt = sp.Matrix(tt) ttd = st.time_deriv(tt, tt, **kwargs) ttdd = st.time_deriv(tt, tt, order=2, **kwargs) # Lagrange function L = T - U if not T.atoms().intersection(ttd) == set(ttd): raise ValueError('Not all velocity symbols do occur in T') # partial derivatives of L L_diff_tt = st.jac(L, tt) L_diff_ttd = st.jac(L, ttd) # prov_deriv_symbols = [ttd, ttdd] # time-depended_symbols tds = list(tt) + list(ttd) L_diff_ttd_dt = st.time_deriv(L_diff_ttd, tds, **kwargs) # constraints constraint_terms = list(llmd.T * jac_constraints) # lagrange equation 1st kind (which include 2nd kind as special case if constraints are empty) model_eq = sp.zeros(n, 1) for i in range(n): model_eq[i] = L_diff_ttd_dt[i] - L_diff_tt[i] - F[i] - constraint_terms[i] model_eq += st.gradient(dissipation_function, ttd).T # create object of model mod = SymbolicModel() # model_eq, qs, f, D) mod.eqns = model_eq mod.extforce_list = F reduced_F = sp.Matrix([s for s in F if st.is_symbol(s)]) mod.F = reduced_F mod.tau = reduced_F if constraints_flag: mod.llmd = llmd mod.constraints = constraints else: # omit fake constraint [0] mod.constraints = None mod.llmd = None # coordinates velocities and accelerations mod.tt = tt mod.ttd = ttd mod.ttdd = ttdd mod.qs = tt mod.qds = ttd mod.qdds = ttdd # also store kinetic and potential energy mod.T = T mod.U = U if simplify: mod.eqns.simplify() return mod
def generate_symbolic_model(T, U, tt, F, simplify=True, **kwargs): """ T: kinetic energy U: potential energy tt: sequence of independent deflection variables ("theta") F: external forces simplify: determines whether the equations of motion should be simplified (default=True) kwargs: optional assumptions like 'real=True' """ n = len(tt) for theta_i in tt: assert isinstance(theta_i, sp.Symbol) F = sp.Matrix(F) if F.shape[0] == 1: # convert to column vector F = F.T if not F.shape == (n, 1): msg = "Vector of external forces has the wrong length. Should be " + \ str(n) + " but is %i!" % F.shape[0] raise ValueError(msg) # introducing symbols for the derivatives tt = sp.Matrix(tt) ttd = st.time_deriv(tt, tt, **kwargs) ttdd = st.time_deriv(tt, tt, order=2, **kwargs) #Lagrange function L = T - U if not T.atoms().intersection(ttd) == set(ttd): raise ValueError('Not all velocity symbols do occur in T') # partial derivatives of L L_diff_tt = st.jac(L, tt) L_diff_ttd = st.jac(L, ttd) #prov_deriv_symbols = [ttd, ttdd] # time-depended_symbols tds = list(tt) + list(ttd) L_diff_ttd_dt = st.time_deriv(L_diff_ttd, tds, **kwargs) #lagrange equation 2nd kind model_eq = sp.zeros(n, 1) for i in range(n): model_eq[i] = L_diff_ttd_dt[i] - L_diff_tt[i] - F[i] # create object of model mod = SymbolicModel() # model_eq, qs, f, D) mod.eqns = model_eq mod.extforce_list = F reduced_F = sp.Matrix([s for s in F if st.is_symbol(s)]) mod.F = reduced_F mod.tau = reduced_F # coordinates velocities and accelerations mod.tt = tt mod.ttd = ttd mod.ttdd = ttdd mod.qs = tt mod.qds = ttd mod.qdds = ttdd # also store kinetic and potential energy mod.T = T mod.U = U if simplify: mod.eqns.simplify() return mod
def generate_model(T, U, qq, F, **kwargs): raise DeprecationWarning('generate_symbolic_model should be used') """ T kinetic energy U potential energy q independend deflection variables F external forces D dissipation function """ n = len(qq) # time variable t = sp.symbols('t') # symbolic Variables (to prevent Functions where we not want them) qs = [] qds = [] qdds = [] if not kwargs: # assumptions for the symbols (facilitating the postprocessing) kwargs = {"real": True} for qi in qq: # ensure that the same Symbol for t is used assert qi.is_Function and qi.args == (t, ) s = str(qi.func) qs.append(sp.Symbol(s, **kwargs)) qds.append(sp.Symbol(s + "_d", **kwargs)) qdds.append(sp.Symbol(s + "_dd", **kwargs)) qs, qds, qdds = sp.Matrix(qs), sp.Matrix(qds), sp.Matrix(qdds) #derivative of configuration variables qd = qq.diff(t) qdd = qd.diff(t) #lagrange function L = T - U #substitute functions with symbols for partial derivatives #highest derivative first subslist = lzip(qdd, qdds) + lzip(qd, qds) + lzip(qq, qs) L = L.subs(subslist) # partial derivatives of L Ldq = st.jac(L, qs) Ldqd = st.jac(L, qds) # generalised external force f = sp.Matrix(F) # substitute symbols with functions for time derivative subslistrev = st.rev_tuple(subslist) Ldq = Ldq.subs(subslistrev) Ldqd = Ldqd.subs(subslistrev) Ldqd = Ldqd.diff(t) #lagrange equation 2nd kind model_eq = qq * 0 for i in range(n): model_eq[i] = Ldqd[i] - Ldq[i] - f[i] # model equations with symbols model_eq = model_eq.subs(subslist) # create object of model model1 = SymbolicModel() # model_eq, qs, f, D) model1.eqns = model_eq model1.qs = qs model1.extforce_list = f model1.tau = f model1.qds = qds model1.qdds = qdds # also store kinetic and potential energy model1.T = T model1.U = U # analyse the model return model1
def generate_model(T, U, qq, F, **kwargs): raise DeprecationWarning('generate_symbolic_model should be used') """ T kinetic energy U potential energy q independend deflection variables F external forces D dissipation function """ n = len(qq) # time variable t = sp.symbols('t') # symbolic Variables (to prevent Functions where we not want them) qs = [] qds = [] qdds = [] if not kwargs: # assumptions for the symbols (facilitating the postprocessing) kwargs ={"real": True} for qi in qq: # ensure that the same Symbol for t is used assert qi.is_Function and qi.args == (t,) s = str(qi.func) qs.append(sp.Symbol(s, **kwargs)) qds.append(sp.Symbol(s + "_d", **kwargs)) qdds.append(sp.Symbol(s + "_dd", **kwargs)) qs, qds, qdds = sp.Matrix(qs), sp.Matrix(qds), sp.Matrix(qdds) #derivative of configuration variables qd = qq.diff(t) qdd = qd.diff(t) #lagrange function L = T - U #substitute functions with symbols for partial derivatives #highest derivative first subslist = lzip(qdd, qdds) + lzip(qd, qds) + lzip(qq, qs) L = L.subs(subslist) # partial derivatives of L Ldq = st.jac(L, qs) Ldqd = st.jac(L, qds) # generalised external force f = sp.Matrix(F) # substitute symbols with functions for time derivative subslistrev = st.rev_tuple(subslist) Ldq = Ldq.subs(subslistrev) Ldqd = Ldqd.subs(subslistrev) Ldqd = Ldqd.diff(t) #lagrange equation 2nd kind model_eq = qq * 0 for i in range(n): model_eq[i] = Ldqd[i] - Ldq[i] - f[i] # model equations with symbols model_eq = model_eq.subs(subslist) # create object of model model1 = SymbolicModel() # model_eq, qs, f, D) model1.eqns = model_eq model1.qs = qs model1.extforce_list = f model1.tau = f model1.qds = qds model1.qdds = qdds # also store kinetic and potential energy model1.T = T model1.U = U # analyse the model return model1