This is an IPyton notebook and it is coded in the Python programming language.
Python has the idea of modules, separate units of code that
provide the programmer with ready to use, tested code.
You can write yourself your modules, or rather use library
modules, in any case you access functions or data defined in
modules import-ing them.
For example, in the next code cell we import three functions
from the math module (and a constant too) and then we do some
other stuff...
import functions and data from math,import all the stuff from sympy (symbolic algebra) under
the prefix sy, and use this convention to initialize the sympy
printing system,import from the submodule IPython.display two utility
functions,import the module style and execute its
function clean that changes the default appearance of a notebook
using some css styling and a small sprinkle of javascript.
In [1]:
%pylab --no-import-all inline
from math import exp, log, pi, sqrt
import sympy as sy ; sy.init_printing(use_latex=True)
from IPython.display import display, Latex
import style ; style.clean()
Out[1]:
What is the analytical expression of the response of a damped system subject to the (quite common) initial conditions $x(0)=x_0$ and $\dot x(0)=0$?
We start by creating a set of symbols and giving them good names...
In [2]:
A, B, t, z, wn, wd, x0 = sy.symbols(
'A, B, t, zeta, omega_n, omega_d, x_0')
display((A, B, t, z, wn, wd, x0))
Then we give the name u to the symbolic representation of the displacement,
and the name v to the first time derivative of u.
In [3]:
u = sy.exp(-z*wn*t)*(A*sy.cos(wd*t)+B*sy.sin(wd*t))
v = u.diff(t).expand().collect(sy.exp(-z*wn*t))
v = v.collect(sy.cos(wd*t)).collect(sy.sin(wd*t))
display(Latex(r'\begin{align*}x(t)&='+sy.latex(u)+r'''\\
\\dot{x}(t) &= '''+sy.latex(v)+r'\end{align*}'))
Now,
u and v and subtracting $x_0$
from the first equation sympy aka sy library to solve the system of equations
In [4]:
eq = (u.subs(t,0)-x0, v.subs(t,0))
coeff = sy.solve(eq, A,B)
display(coeff)
display(u.subs(coeff).collect(x0))
display(u.subs(coeff).collect(x0).subs(wn,wd/sy.sqrt(1-z*z)))
To plot the response we need to get rid of all the symbols in our expression, except for $t$, so we choose an arbitrary set of values for the free variables...
In [5]:
values = {x0:1.0, z:0.05, wd:2*sy.pi, wn:2*sy.pi/sy.sqrt(1-z*z)}
values[sy.pi] = sy.pi.evalf()
display(values)
At the end, we display the analytical expression of $x(t)$ and plot
$x(t)$,
$\dot x(t)$.
In [6]:
display(u.subs(coeff).subs(values))
sy.plot(u.subs(coeff).subs(values), (t,0,5.99));
sy.plot(v.subs(coeff).subs(values), (t,0,5.99) );
We assume that our system has been deformed by the application of some static load, so that at time $t=0$ the initial conditions are $x(0)=x_0$ and $\dot x(0)=0$.
At $t=0$ the static force is suddenly released, we observe an oscillatory behaviour as we have detailed in the preceding section.
and we are able to measure the peak displacement after $n$ cycles, $x_n$.
The following code gives appropriate names to values measured or computed from expressions, the value of the logarithmic decrement is eventually printed.
In [7]:
n = 3
x0 = 8.00
xn = 3.11
dn = log(x0/xn)
print "delta_n =",dn
The exact expression for $\zeta$ is
$$ \zeta = \sqrt{\frac{\delta_n^2}{(2 n \pi)^2 + \delta_n^2}} \text{ with } \delta_n = \log\frac{x_0}{x_n}.$$We've already computed $\delta_n$ in the previous code cell so we can write the numerator and the denominator of the radicand and eventually compute the "exact" value of $\zeta$.
In [8]:
num = dn*dn
den = 4 * n*n * pi*pi + dn*dn
z = sqrt(num/den)
print "zeta = %f"%(z*100,)
The linearized expression for $\zeta$, that we have found using the first and second terms of the McLaurin series expressing $\exp(a\zeta)=1+a\zeta$, is
$$\zeta \approx \frac{1}{2 n \pi}\,\frac{x_0-x_n}{x_n}.$$We know that this approximation is good for low damping and few cycles...
In [9]:
print "Estimate", 100 * (x0-xn) / xn / ( 2*n* pi )
print "error (z/est.)",z /((x0-xn) / xn / ( 2*n* pi ))
We write, formally,
$$\zeta = \xi\sqrt{1-\zeta^2}, \qquad\text{with }\xi = \frac{1}{2 n \pi} \log\frac{x_0}{x_n}$$and derive an iterative formulation
$$\zeta_{i+1} = \xi\sqrt{1-\zeta_i^2}, \qquad\text{with } i = 0, 1, 2, \ldots$$Note that, for $\zeta_0 = 0$, it is $\zeta_1 = \xi$.
In theory, we have to check the convergence of the sequence and stop when the
convergence is reached, but in our cases the convergence is soo fast that we
are safe implementing the solution in a for loop
In [10]:
csi= dn/2/n/pi
z_i = csi
print " zeta_0 = 0.00000000000000%"
print "csi = zeta_1 = %16.14f%%" % (csi*100,)
for i in range(2, 6):
z_i = csi*sqrt(1-z_i*z_i)
print ' zeta_%d = %16.14f%%'%(i,100*z_i)