Panel flutter analysis#
The aerodynamic stiffness matrix of the linear piston theory is calculated
with Shell.calc_kA(), as a function of the aerodynamic parameter
beta of the Shell object. The flutter onset is found by
increasing beta and solving the eigenvalue problem
\((\boldsymbol{K}_C + \boldsymbol{K}_G + \boldsymbol{K}_A + \lambda^2 \boldsymbol{M})\boldsymbol{c} = \boldsymbol{0}\) with
structsolve.freq(), until two natural frequencies coalesce and the
eigenvalues become complex. In this convention \(\boldsymbol{K}_A = -\int \left(\beta
(\boldsymbol{S}^w_{,x})^\top \boldsymbol{S}^w + \gamma (\boldsymbol{S}^w)^\top
\boldsymbol{S}^w\right) dA\), with the row \(\boldsymbol{S}^w\) of the
approximation functions of \(w\), for the load
\(q = \beta w_{,x} + \gamma w\) of a flow along \(x\), where the curvature
correction \(\gamma\) of Krumhaar softens a cylindrical shell, see
Shell.calc_kA(). The term in \(\beta\) is the transpose of that of Eq.
(21) of [castro2016FlutterPanel], which for \(w = 0\) at the leading and
trailing edges corresponds to reversing the flow direction and does not
change the flutter boundary, whereas the sign of the term in \(\gamma\) of
Eqs. (21) and (29) of that paper is reversed, a mistake of the paper. The
aerodynamic damping, Shell.calc_cA(), is \(i \boldsymbol{C}_A\) with \(\boldsymbol{C}_A\) of
Eq. (23) of the paper, entering the eigenvalue problem as \(+\omega \boldsymbol{C}_A\).
The code below is extracted from one of the panels unit tests, which
verifies the critical beta with and without pre-stress:
def test_aero():
for model in ['plate_clpt_donnell',
'cylshell_clpt_donnell',
'cylshell_clpt_sanders',
'plate_fsdt_donnell',
'plate_tsdt_donnell']:
for pre_stress in [False, True]:
print('Flutter Analysis Piston Theory, consider_pre_stress={0}, model={1}'.
format(pre_stress, model))
s = Shell()
s.model = model
s.a = 1.
s.b = 0.5
s.r = 1.e8
s.stack = [0, 90, -45, +45]
s.plyt = 1e-3*0.125
E2 = 8.7e9
s.laminaprop = (142.5e9, E2, 0.28, 5.1e9, 5.1e9, 5.1e9)
s.rho = 1.5e3
s.m = 8
s.n = 9
if pre_stress:
s.Nxx = -60.
s.Nyy = -5.
else:
s.Nxx = 0
s.Nyy = 0
# testing commong methodology based on betastar
if pre_stress:
betasstar = np.linspace(50, 350, 40)
else:
betasstar = np.linspace(300, 690, 40)
betas = betasstar/(s.a**3/E2/(len(s.stack)*s.plyt)**3)
s.beta = betas[0]
kC = s.calc_kC()
kG = s.calc_kG()
kA = s.calc_kA()
kM = s.calc_kM()
eigvals, eigvecs = freq(kC + kG + kA, kM, sparse_solver=True, silent=True)
out = np.zeros((len(betasstar), eigvals.shape[0]),
dtype=eigvals.dtype)
for i, beta in enumerate(betas):
s.beta = beta
kA = s.calc_kA()
eigvals, eigvecs = freq(kC + kG + kA, kM, sparse_solver=True, silent=True)
omegan = (-eigvals)**0.5
omegan = omegan*s.a**2/(np.pi**2*sum(s.plyts))*np.sqrt(s.rho/E2)
out[i, :] = omegan
ind = np.where(np.any(out.imag != 0, axis=1))[0][0]
if pre_stress:
assert np.isclose(betas[ind], 129.663, atol=0.1, rtol=0)
else:
assert np.isclose(betas[ind], 358.875, atol=0.1, rtol=0)