Tutorial - Time and Frequency Analyzes#
This is the third part of a basic tutorial on how to use ROSS (rotordynamics open-source software). In this tutorial, you will learn how to run time and frequency analyzes with your rotor model.
To get results, we always have to use one of the .run_ methods available for a rotor object. These methods will return objects that store the analysis results and that also have plot methods available. These methods will use the plotly library to make graphs common to a rotordynamic analysis.
We can also use units when plotting results. For example, for a unbalance response plot we have the amplitude_units argument and we can choose between any length unit available in pint such as ‘meter’, ‘inch’, etc.
Rotor model#
Again, let’s recover the rotor model built in the previous tutorial.
import ross as rs
from ross.units import Q_
from ross.probe import Probe
import numpy as np
# Make sure the default renderer is set to 'notebook' for inline plots in Jupyter
import plotly.io as pio
pio.renderers.default = "notebook"
rotor3 = rs.compressor_example()
rotor3.plot_rotor(nodes=5)
C:\Users\vinic\OneDrive\Desktop\Digital_Twin\Github\ross\ross\rotor_assembly.py:4082: UserWarning:
File was created with ROSS 2.0.0, but current version is 2.2.0. This may lead to incompatibilities.
Rotor Analyses#
There’re some methods, most of them with the prefix run_ you can use to run the rotordynamics analyses. For Most of the methods, you can use the command .plot() to display a graphical visualization of the results (e.g run_freq_response().plot()).
ROSS offers the following analyses:
Frequency response
Unbalance response
Time response
Undamped Critical Speed Map
Plotly library#
ROSS uses Plotly for plotting results. All the figures can be stored and manipulated following Plotly API.
The following sections presents the results and how to return the Plotly Figures.
1.1 Frequency Response#
ROSS’ method to calculate the Frequency Response Function is run_freq_response(). This method returns the magnitude and phase in the frequency domain. The response is calculated for each node from the rotor model.
When plotting the results, you can choose to plot:
amplitude vs frequency:
plot_magnitude()phase vs frequency:
plot_phase()polar plot of amplitude vs phase:
plot_polar_bode()all:
plot()
Note: By default, frequency response curves are drawn with straight line segments between the sampled frequencies (line_shape="linear" in Plotly). If you want a visually smoother curve without changing the underlying sampling, you can pass the optional line_shape argument to plot_magnitude(), for example: line_shape="spline".
1.1.2 Running frequency response#
To run the this analysis, use the command run_freq_response(). You can give a specific speed_range or let the program run with the default options. In this case, no arguments are needed to input.
First, let’s run an example with a “user-defined” speed_range. Setting an array to speed_range will disable all the frequency spacing parameters.
samples = 61
speed_range = np.linspace(315, 1150, samples) # rads/s
results1 = rotor3.run_freq_response(speed_range=speed_range)
C:\Users\vinic\OneDrive\Desktop\Digital_Twin\Github\ross\ross\rotor_assembly.py:1368: UserWarning:
Extrapolating bearing coefficients. Be careful when post-processing the results.
results1.speed_range.size
61
In the next section we’ll check the difference between both results.
1.1.3 Plotting results - Bode Plot#
We can plot the frequency response selecting the input and output degree of freedom.
Input is the degree of freedom to be excited;
Output is the degree of freedom to be observed.
Each shaft node has 6 local degrees of freedom (dof) \([x, y, z, \alpha, \beta, \theta]\), and each degree of freedom has it own index:
\(x\) → index 0
\(y\) → index 1
\(z\) → index 2
\(\alpha\) → index 3
\(\beta\) → index 4
\(\theta\) → index 5
To select a DoF to input and a DoF to the output, we have to use the following correlation:
\(global\_dof = node\_number \cdot dof\_per\_node + dof\_index\)
For example: node 26, global dof \(y\):
node = 26
global_dof = node * rotor3.number_dof + 1
plot = results1.plot(inp=global_dof, out=global_dof)
plot
# converting the first plot yaxis to log scale
# plot = results1.plot(inp=global_dof, out=global_dof)
# plot.update_yaxes(type="log", row=1, col=1)
# plot
# plot1_2 = results1_2.plot(inp=global_dof, out=global_dof)
# plot1_2
# # converting the first plot yaxis to log scale
# plot1_2 = results1_2.plot(inp=global_dof, out=global_dof)
# plot1_2.update_yaxes(type="log", row=1, col=1)
# plot1_2
1.2 Unbalance Response#
ROSS’ method to simulate the reponse to an unbalance is run_unbalance_response(). This method returns the unbalanced response in the frequency domain for a given magnitide and phase of the unbalance, the node where it’s applied and a frequency range.
ROSS takes the magnitude and phase and converts to a complex force array applied to the given node:
where:
\(F\) is the unbalance magnitude;
\(\delta\) is the unbalance phase;
\(j\) is the complex number notation;
When plotting the results, you can choose to plot the:
Bode plot options for a single degree of freedom:
amplitude vs frequency:
plot_magnitude()phase vs frequency:
plot_phase()polar plot of amplitude vs phase:
plot_polar_bode()all:
plot()
Deflected shape plot options:
deflected shape 2d:
plot_deflected_shape_2d()deflected shape 3d:
plot_deflected_shape_3d()bending moment:
plot_bending_moment()all:
plot_deflected_shape()
1.2.1 Running unbalance response#
To run the Unbalance Response, use the command .unbalance_response()
In this following example, we can obtain the response for a given unbalance and its respective phase in a selected node. Notice that it’s possible to add multiple unbalances instantiating node, magnitude and phase as lists.
The method returns the force response array (complex values), the displacement magnitude (absolute value of the forced response) and the phase of the forced response.
Let’s run an example with 2 unbalances in phase, trying to excite the first and the third natural vibration mode.
Unbalance1: node = 29
magnitude = 0.003
phase = 0
Unbalance2: node = 33
magnitude = 0.002
phase = 0
n1 = 29
m1 = 0.003
p1 = 0
n2 = 33
m2 = 0.002
p2 = 0
frequency_range = np.linspace(315, 1150, 101)
results2 = rotor3.run_unbalance_response([n1, n2], [m1, m2], [p1, p2], frequency_range)
1.2.2 Plotting results - Bode Plot#
To display the bode plot, use the command .plot(probe)
Where probe is a list of Probe objects that allows you to choose not only the node where to observe the response, but also the orientation.
Probe orientation equals 0° refers to +X direction (DoFX), and probe orientation equals 90° (or \(\frac{\pi}{2} rad\)) refers to +Y direction (DoFY).
You can insert multiple probes at once.
# probe = Probe(probe_node, probe_orientation)
probe1 = Probe(15, Q_(45, "deg")) # node 15, orientation 45°
probe2 = Probe(35, Q_(45, "deg")) # node 35, orientation 45°
results2.plot(probe=[probe1, probe2])
# converting the first plot yaxis to log scale
# plot2 = results2.plot(probe=[probe1, probe2], probe_units="rad")
# plot2.update_yaxes(type="log", row=1, col=1)
# plot2