The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
Simulating a network of (damped) harmonic oscillators as described in Wikipedia over time. A connection between two oscillators consists of a damper and a spring. It is possible to insert events over time.
Our task is the simulation of a single harmonic oscillator.
We define an oscillator with a mass which is connected to a spring and a damper.
mass = 1
damper = matrix(0.1)
spring = matrix(1)
odenet = ODEnetwork(masses = mass, dampers = damper, springs = spring)
In the next step, it is necessary to define the start conditions.
Finally, we run the simulation over a time interval of 20 seconds and plot the result of the first state, which is the position of the oscillator.
This looks a bit ugly, because ODEnetwork
calculates the position (state1) of the oscillator for the times given in vector times
. The calculation for every time stamp is correct, because the solution is calculated in an analytic way:
We can improve the smoothness by using a time vector with smaller steps.
Complexer questions handle connected oscillators instead of one. It is interesting, to simulate the behaviour of each oscillator connected to the others in a network of oscillators. Here we take a closer look at three oscillators which are connected in a row. That means, oscillator 1 is connected with oscillator 2, which is connected to oscillator 3.
As in the section above, we define the masses, dampers, and springs. Additionally, it is necessary to define connections between the oscillators. The corresponding values are set to the off-diagonal elements in the variables damper
and spring
.
mass = 1:3
damper = diag(rep(0.1, 3))
damper[1, 2] = 0.1
damper[2, 3] = 0.1
spring = diag(rep(1, 3))
spring[1, 2] = 1
spring[2, 3] = 1
odenet = ODEnetwork(masses = mass, dampers = damper, springs = spring)
In the next step, it is necessary to define the start conditions for the two states which are the position and velocity of each oscillator.
Finally, we run the simulation over a time interval of 20 seconds and plot the result of the first state, which is the position of the oscillator.
It is possible to take a look at the position x.1
and velocity v.1
in one graph:
To calculate the resonance frequencies of each oscillator we call the function calcResonances()
.
By default all springs in these networks have the length 0. Using the variable distances
in ODEnetwork
or updateOscillators
we can define values for the spring length. Sometimes it is necessary to calculate these distances from an equilibrium state. So, what would be a possible set of spring length, if we provide an equilibrium state? We can calculate this via the function estimateDistances()
.
odenet = estimateDistances(odenet, equilibrium = c(1, 2, 3))
odenet$distances
#> [,1] [,2] [,3]
#> [1,] 2.000000 1.555628 0.000000
#> [2,] 1.555628 2.000000 1.555628
#> [3,] 0.000000 1.555628 2.000000
odenet = estimateDistances(odenet, equilibrium = c(1, 2, 3), distGround = "individual")
odenet$distances
#> [,1] [,2] [,3]
#> [1,] 0.3116121 0.6882909 0.0000000
#> [2,] 0.6882909 1.9998933 0.6886108
#> [3,] 0.0000000 0.6886108 3.6884944
The first calculation defines the spring length from the ground (or reference point) equally. It estimates the spring length between the oscillators with one value, because all spring constants are equal. The second calculation enables the estimation to calculate individual length to the reference point, which effects the distances between the oscillators, too.
All calculations in the examples above are done from a defined starting point over time in an analytical way. In some applications it is interesting to interact with the oscillators during the simulation. The following example uses two connected oscillators.
mass = c(1, 2)
damper = diag(c(0.02, 0.1))
damper[1, 2] = 0.1
spring = diag(c(4, 1))
spring[1, 2] = 2
distance = matrix(c(0, 0, 1, 0), ncol = 2)
odenet = ODEnetwork(mass, damper, spring, distances = distance)
odenet = setState(odenet, c(1, 1), c(0, 0))
odenet = simuNetwork(odenet, seq(0, 20, by = 0.01))
Here we see the positions over time without interactions during the simulation.
In the next step, we define some events and assign the to the network. The following data.frame
defines events for the position of the first oscillator. Using the setEvents
method, we assign the events to the network. The type
parameter is set to linear
, hence the coordinates defined by time
and value
are connected using a linear function. We see the effect of this parameter in the next plot. After setting everything, the simulation has to be recalculated again.
eventdata = data.frame(var = c("x.1", "x.1", "x.1")
, time = c(5, 10, 12)
, value = c(0, 1, 1)
, stringsAsFactors = TRUE
)
odenet = setEvents(odenet, eventdata, type = "constant")
odenet = simuNetwork(odenet, seq(0, 20, by = 0.01))
plot(odenet, state = "1")
As we see in the plot, the position of the oscillator is set to 0 at time 5 seconds. After 10 seconds the position is set to 1 and the oscillator changes its position in a linear way. Change the values of the parameter type
to dirac
or constant
to get an idea of their different behaviour.
These calculations are done in a numeric way. We see this in the following variable of odenet
which describes the used calculation method.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.