OpenSees Cloud
OpenSees AMI
Minimal Random Process Example
Original Post - 28 Sep 2025 - Michael H. Scott
Show your support at Buy Me a Coffee.
I know just enough about random vibrations and ground motions to be dangerous. I would like to become less of a liability on these topics, so bear with me on this post.
OpenSees has two time series for random processes, both implemented by
Terje Haukaas.
A DiscretizedRandomProcess
uses random variables to construct a time
series from filtered unit impulse response functions and a
SimulatedRandomProcess
passes randomly generated numbers through a
spectrum
object that encapsulates a power spectral density (PSD)
function.
This post will focus on constructing a SimulatedRandomProcess
in
OpenSees, for which the available PSD functions are narrowband
,
jonswap
, and points
.
The narrowband
spectrum has constant spectral density over a specified
frequency range. For example, to define a constant PSD of 0.001
m2/s3 over a frequency range of 0.5 to 20 Hz, we use
the following spectrum
command.
import openseespy.opensees as ops
from math import pi
wmin = 0.5*(2*pi) # rad/sec
wmax = 20*(2*pi) # rad/sec
Sd = 0.001 # m^2/sec^3
ops.spectrum(1,'narrowband',wmin,wmax,Sd)
Yeah, the tag comes before the type.
The jonswap
spectrum implements an empirical wave energy relationshp
from the Joint North Sea Wave Project (JONSWAP). It’s kinda funny that
the jonswap
spectrum was OpenSees’s first homage to waves, long before
the fluid-structure interaction capabilties of the PFEM came on board.
The points
spectrum is based on user input (frequency, PSD) pairs.
Until it is implemented directly in OpenSees, the points
spectrum is
the only approach for the Kanai-Tajimi spectrum or any other spectrum
besides JONSWAP. No big deal.
Anyway, after defining a spectrum, we can define a
SimulatedRandomProcess
time series. In addition to the spectrum tag,
we pass the mean value for the process (usually zero when generating
ground motions) and the number of sampling points for the PSD function.
The sampling points are uniformly spaced across the frequency range of
the spectrum.
spectrumTag = 1
mean = 0.0
Nfreq = 200
ops.timeSeries('SimulatedRandomProcess',1,spectrumTag,mean,Nfreq)
The synthetic ground acceleration record created from the foregoing
narrowband
spectrum and SimulatedRandomProecess
time series commands
is shown below.
It doesn’t look like it, but the time series is the summation of 200 randomly generated sine waves with frequencies uniformly distributed between 0.5 and 20 Hz. White noise.
Then, we pass the time series to a UniformExcitation
load pattern (or
any other load pattern such as MultiSupport or Plain if you are so
inclined). Putting it all together in an SDF analysis, we have the following.
ops.wipe()
ops.model('basic','-ndm',1,'-ndf',1)
m = 1
ops.node(1,0); ops.fix(1,1)
ops.node(2,0); ops.mass(2,m)
wn = 10.0 # Or whatever
zeta = 0.03 # Or whatever
k = m*wn**2
c = 2*m*wn*zeta
ops.uniaxialMaterial('Elastic',1,k,c)
ops.element('zeroLength',1,1,2,'-mat',1,'-dir',1)
# Defined above
ops.spectrum(1,'narrowband',wmin,wmax,Sd)
ops.timeSeries('SimulatedRandomProcess',1,spectrumTag,mean,Nfreq)
ops.pattern('UniformExcitation',1,1,'-accel',1)
ops.analysis('Transient','-noWarnings')
Tfinal = 40
dt = 0.01
Nsteps = int(Tfinal/dt)
for i in range(Nsteps):
ops.analyze(1,dt)
The displacement response history for an SDF system at natural circular frequency 10 rad/sec and 3% damping is shown below.
The response follows the periodicity of the synthetic excitation.
The SDF response spectrum produced by the same SimulatedRandomProcess
time series is shown below for 3% damping.
Outside the 0.5-20 Hz frequency range used to construct the synthetic excitation, the spectral acceleration falls off rapidly to zero for low frequencies and to the PGA for high frequencies.
If you re-create the analysis shown in this post, your results will be
different because the SimulatedRandomProcess
time series uses a random
number generator.
For more details on the random process capabilities in OpenSees, check out PEER report 2003/14 by Haukaas and Der Kiureghian.