[ANN] StructuralVibration.jl

Hi all,

I am pleased to announce my first real contribution to the Julia environment. StructuralVibration.jl is intended to provide a set of tools for generating vibration data either to validate new numerical methods or to serve as input data for solving inverse problems such as input state estimation via Bayesian filtering, Bayesian regularization, machine learning, etc.

This package is developed as part of my research activities on source identification in structural dynamics and acoustics. It has been tested with DispatchDoctor.jl and Aqua.jl.

I tried to developed a comprehensive documentation that you can read here.

The package provides the following features:

Mechanical models

  • Discrete models
    • Spring-mass-damper of SDOF and MDOF systems
    • FE models of bar, rod, strings and beams
  • Continuous models
    • Longitudinal bars, Torsional bars, Strings
    • Beams
    • Rectangular plates, Rectangular membranes
  • State space model
    • Continuous state-space representation
    • Discrete state-space representation
      • Zero-order hold (ZOH)
      • First-order hold (FOH)
      • Band-limited hold (BLH)
      • RK4

Vibration data generation

  • Excitation signals

    • Rectangular wave
    • Triangular wave
    • Hammer impact
    • Smoothed rectangular wave
    • Sine wave
    • Half-sine pulse
    • Harversine pulse
    • Swept sine wave
    • Gaussian pulse
    • Colored noise
  • Solution for SDOF systems

    • Free response
    • Forced response due to a harmonic force or a base motion
    • Forced response due to any external force or base motion (Duhamel’s integral)
  • Time-domain integration schemes for linear second order systems

    • Central difference scheme
    • RK4
    • Newmark-beta method
    • Linear acceleration method
    • Fox-Goodwin method
    • HHT
    • WBZ
    • Generalized-alpha
    • Mid-Point rule
  • Frequency-domain calculations for linear systems

    • Frequency spectrum
      • Modal summation
      • Direct method
    • Frequency response function (FRF)
      • Modal summation
      • Direct method
  • State-space solvers

    • Time domain
      • RK4 for continuous systems
      • ZOH, FOH, BLH, RK4 for discrete models
    • Frequency spectrum
      • Modal summation
      • Direct method
    • Frequency response function (FRF)
      • Modal summation
      • Direct method
  • Measurement noise

    • Additive Gaussian white noise (agwn) with a prescribed SNR
    • Additive Colored noise (acn)
    • Multiplicative noise
    • Mixed - agwn + multiplicative noise
  • Signal processing

    • Measurement noise variance estimation algorithms from noisy data
    • SNR estimation from estimated measurement noise variance
    • Denoising algorithms
      • Regularization
      • Kalman filtering
    • Modal extraction - SDOF methods
      • Peak picking method
      • Circle fit method
    • Detrending data using polynomial fit
    • Gradient calculation using interpolation
    • Signal estimation
      • Transfer functions estimation (H1, H2, H3, Hv)
      • Welch method (PSD, ESD, Autopower, Autopower linear)
      • Signal spectrum estimation

Visualization

  • Bode plot
  • 2D and 3D Nyquist plot
  • Waterfall plot
  • General 2D plot

PR are welcome !

18 Likes

Thanks to @Krastanov for mentioning your package, otheriwise I would have missed it.

I tried loading it and received the error

(@v1.11) pkg> dev StructuralVibration
ERROR: The following package names could not be resolved:
 * StructuralVibration (not found in project, manifest or registry)
   Suggestions: StructuredOptimization StructuralEquationModels StructuralUnits StructureFunctions StructuralInheritance

(@v1.11) pkg> add StructuralVibration
ERROR: The following package names could not be resolved:
 * StructuralVibration (not found in project, manifest or registry)
   Suggestions: StructuredOptimization StructuralEquationModels StructuralUnits StructureFunctions StructuralInheritance

(@v1.11) pkg> 

This however works:

https://github.com/maucejo/StructuralVibration.jl)

The documentation should be updated.

You are right. I will update. However, you can just type add StructuralVibration to install the package.

I’m trying to simulate s string, but I’m hitting an error. What do I do wrong?

using StructuralVibration

# Defining String
L = 1.
d = 3e-2
S = π*d^2/4
T = 5000.
ρ = 7800.
strings = Strings(L, S, T, ρ)

# Mesh definition
oned_mesh = OneDMesh(strings, 0., 20, :CC)

# Construction of K and M
Kfe, Mfe = assembly(strings, oned_mesh)

# Application of the BCs
Kbc = apply_bc(Kfe, oned_mesh)
Mbc = apply_bc(Mfe, oned_mesh)

# Calculation of the damping matrix
Cray = rayleigh_damping_matrix(Kbc, Mbc, 1., 1.)

t = 0.:1e-2:30.

# pull middle node
x0 = [zeros(10); .1; zeros(10)]  
v0 = zeros(21) # length(oned_mesh.Nodes)
u0 = (x0, v0)

# No force
F_free = zeros(length(oned_mesh.Nodes), length(t))

# Direct time problem
prob = DirectTimeProblem(Kfe, Mfe, Cray, F_free, u0, t)

x_free = solve(prob)

ERROR: DimensionMismatch: incompatible dimensions for matrix multiplication: tried to multiply a matrix of size (19, 19) with a vector of length 21. The second dimension of the matrix: 19, does not match the length of the vector: 21.

The mismatch is probably between the stiffness / mass matrix of size (21,21) with the dampening matrix of size (19,19).

What am I missing?

Hi @tp2750, there are several places in the code where you have a problem with dimensions:

  • You apply the BCs to obtain Kbc and Mbc but you don’t use it in the definition of DirectTimeproblem
  • The initial conditions have improper dimensions it should be 19 instead of 21. Same for F_free.
1 Like

Thank you for the quick reply @Maucejo .That makes sense.

But I still don’t understand the solution: the string seems to be accelerating:

using StructuralVibration

# Defining String
L = 1.
d = 3e-2
S = π*d^2/4
T = 5000.
ρ = 7800.
strings = Strings(L, S, T, ρ)

# Mesh definition
oned_mesh = OneDMesh(strings, 0., 20, :CC)

# Construction of K and M
Kfe, Mfe = assembly(strings, oned_mesh)

# Application of the BCs
Kbc = apply_bc(Kfe, oned_mesh)
Mbc = apply_bc(Mfe, oned_mesh)

# Calculation of the damping matrix
Cray = rayleigh_damping_matrix(Kbc, Mbc, 1., 1.)

t = 0.:1e-2:30.

# pull middle node
x0 = [zeros(9); .1; zeros(9)]  
v0 = zeros(19) 
u0 = (x0, v0)

# No force
F_free = zeros(19, length(t))

# Direct time problem
prob = DirectTimeProblem(Kbc, Mbc, Cray, F_free, u0, t)

res = solve(prob, RK4())

res.u[10,1:10]
# 10-element Vector{Float64}:
#   0.1
#  -1.8784032029609778e9
#  -8.401071302860451e25
#  -1.1089726996095221e43
#  -2.134285418196705e60
#  -4.314418943294794e77
#  -8.76890712758781e94
#  -1.7835251743719702e112
#  -3.6279960099309237e129
#  -7.380157835402002e146

I would expect the amplitude of the middle element to decrease over time, not increase.

How am I holding it wrong?

@tp2750 I will check that tomorrow but I noticed that you only check the solution over the first 0.1 s. Did you plot the solution over the whole duration ?

Thanks @Maucejo . Yes, I plotted the full time trajectory and it is all NaN after about 0.5 sec or so.

I quickly checked. It seems that there are some instabilities. I have to admit that I don’t know why at the moment…

Thanks for checking @Maucejo . I wanted to try and generate sound from the models to hear if the string sounds like a string. It’s not urgent, but I’ll be happy to learn how to do it correctly. I would love to try to do some ā€œphysical modelingā€ sound synthesis based on this.

I also tried the other models (rod, bar, beam) and the state space solvers. I got instabilities like this in all cases. But the examples in the documentation work (of course).

The problem is probably related to the choice of the timestep. When you have a fixed time step, the choice is related to the critical time step which depends on the numerical scheme considered. When using finite element modeling it is related to the eigenvalues of the smallest element in the mesh.

As an alternative, you can use a modal solver, e.g. FreeModalTimeProblem, which is based on analytical formula or try to construct the state space matrices from the FE matrices and use it DifferentialEquations.jl which use adaptive time stepping.

That being said, I will check the construction of the FE matrices and make an example in the documentation using FE matrices.

1 Like

Thanks for you help @Maucejo . An example in the documentation would be great!

I have updated the documentation to include an example using DifferentialEquations.jl. I also fixed a bug in the solve function for the Newmark family. You can update the package to v1.4.

1 Like

Thanks a lot @Maucejo .
Looking forward to reading and testing :smile:

And thank you for a great package with excellent documentation!

1 Like

Now I can simulate my sting :smile:
However, I get a lot more damping than I would expect :thinking:

I found parameters for a guitar string in https://www.eurecom.fr/publication/8193/download/sec-publi-8193.pdf

Parameters for a nylon string B3 (247 Hz)

  • L = 0.65 m
  • µ = 0.000582 kg māˆ’1
  • T = 60 N
  • Diameter: d = 0.69 mm = 6.9 Ɨ 10āˆ’4m

modefreq agrees:

using StructuralVibration

L = .65
d = 6.9E-4
# Section features
S = π*d^2/4
# Tension for string
T = 60.
# Material
ρ = 0.000582/S

modefreq(Strings(L, S, T, ρ), 1000.)[1]/2pi
# 4-element Vector{Float64}:
#  246.98511502612902
#  493.97023005225805
#  740.9553450783872
#  987.9404601045161

It can also be solved now (takes about a sec):

"""
   Pick a structure. Solve using generalized alpha method
"""
function pick_ga(m; d = 1E-3, bc = :CC, elements = 20)
    oned_mesh = OneDMesh(m, 0., elements, bc)
    
    # Construction of K and M
    Kfe, Mfe = assembly(m, oned_mesh)
    
    # Application of the BCs
    Kbc = apply_bc(Kfe, oned_mesh)
    Mbc = apply_bc(Mfe, oned_mesh)
    nddl = size(Kbc, 1)
    
    # Calculation of the damping matrix
    Cbc = rayleigh_damping_matrix(Kbc, Mbc, 1e-4, 5e-4)
    
    # 4.2 Problem solution
    # Time vector
    t = 0.:1e-5:1.
        nt = length(t)
    
    # Initial conditions
    x0 = d*ones(nddl)
    # x0 = zeros(nddl) ## 1e-3ones(nddl)
    # x0[div(nddl,2)] = d # pick middle element
    v0 = zeros(nddl)
    u0 = (x0, v0)
    
    # Direct time problem - Generalized-alpha method
    prob = DirectTimeProblem(Kbc, Mbc, Cbc, u0, t)
    (; t, res=solve(prob)) 
end

t,s1 = pick_ga(Strings(L, S, T, ρ); d=1E-2) 

# (t = 0.0:1.0e-5:1.0, res =   StructuralVibration.DirectTimeSolution{Float64}
#     u: 19Ɨ100001 Matrix{Float64} [0.01, 0.01, 0.01, 0.01, 0.01]...
#     du: 19Ɨ100001 Matrix{Float64} [0.0, 0.0, 0.0, 0.0, 0.0]...
#     ddu: 19Ɨ100001 Matrix{Float64} [-1.5691528380771137e6, 420453.2360393165, -112660.10608015256, 30187.18828129456, -8088.647045024554]...
# )

However, the ā€œsoundā€ dies very quickly (in about 20 ms):

using Plots
plot(
    plot(t, s1.u[10,:], label="y(t) Element 10"),
    plot(t[100:5000], s1.u[19,100:5000], label="y(t) e 10 @ (0.01-0.05s)"),
    plot([s1.u[:,400] s1.u[:,600]], label=["0.004s" "0.006s"]),
    layout=(3,1)
)

I thought it might be a discretization problem, but I get exactly the same using 100 elements (takes 20 sec to run)

t,s100 = pick_ga(Strings(L, S, T, ρ); d=1E-2, bc = :CC, elements = 100)
plot(
    plot(t, s100.u[50,:], label="y(t) Element 50"),
    plot(t[100:5000], s100.u[50,100:5000], label="y(t) e 50 @ (0.01-0.05s)"),
    plot([s100.u[:,400] s100.u[:,600]], label=["0.004s" "0.006s"]),
    layout=(3,1)
)

Is this as expected?

Oh, It’s the damping of course.

Any idea what that should be for a guitar string?

Any guitar string will be damped. Just mess with the constants till you get something you like.

The parameters I used for Rayleigh damping are completely random. The package allows to compute the coefficient alpha and beta given two resonance frequencies and the corresponding modal damping. Another possible approach is to use modal damping matrix using a low damping ratio.

It should however be mentioned that the string model is purely linear. In practice, I think that a nonlinear model will give you a more realistic result from a perceptual perspective.

2 Likes