## Intro

I’ve been working on this off and on for awhile. Simulator is a Ruby gem which provides functionality for creating discrete time models, and running those models. You can find the Homepage for the Simulator gem on Github.

Take the following two examples included with the gem.

## Ball Drop

Let’s say we want to model a ball that is dropped. Assuming I’m not modeling any bounces, I just need to show the affect of acceleration due to gravity on the position of the ball in space. Position is a function of velocity, which is a function of acceleration. We can model this system using the gem thusly.

# We create a model that simulates a ball drop model = Simulator::Model.new do name = "Ball drop model" # create a couple static variables to represent acceleration with # default values var :ax, 0 var :ay, - 9.8 # create dynamic variables bound to some computation, with default # values. # velocity is affected by acceleration eqtn(:vx, 20) { vx + ax } eqtn(:vy, 50) { vy + ay } # position is affected by velocity eqtn(:x, 10) { x + vx } eqtn(:y, 100) { y + vy } end

There is a simple DSL provided that makes creating the models easier. Hopefully it’s easy enough to follow. We initialize two static variables, ax and ay, which are set to 0 and -9.8, respectively (acceleration due to gravity is equal to -9.8m/s^2.)

Next, we create two “equations”. These are just dynamic variables, variables that depend on the values of other variables, or on some sort of computation. Note that we just pass regular ruby blocks to the eqtn method. These could really perform any ruby code. The result of the block gets stored in the variable given as a symbol. So, we state that the variable vy is dependent on a the addition of vy + ay. vy + ay will be the sum of the values vy and ay from the previous period. We do the same for vx.

Finally, the position of the ball, the coordinates x and y, depend on the velocity. We also set the default initial position of (10, 100).

Next, we create a “run” of the model, and step it 10 periods. This would be the equivalent of 10 seconds (because of what we set acceleration to).

model_run = model.new_run model_run.step 10

Note that although we do not do so here, we could alter the values of run variables in each period, like so:

model_run.set ax: 5 model_run.step

This would give the ball an acceleration in the x direction, and this value would be propagated through subsequent periods (because the variable is static).

Once we have stepped the run, we can request the series data in case we want to plot it. We can retrieve and plot the data like so:

xs, ys = model_run.data.series :x, :y require 'chunky_png' image = ChunkyPNG::Image.new @width, @height, ChunkyPNG::Color::BLACK pts.each do |pt| x, y = pt # flip y due to inverted coordinate system y = @height - y image.circle x, y, 3, ChunkyPNG::Color('red') end image.save filename

and we’d get something like this:

## Mortgages

A mortgage involves a balance, loan payment, and interest rate. Let’s create a model for that.

model = Model.new do name = "Mortgage model" # monthly steps var :base_rate, 0.08 eqtn(:annual_rate) { base_rate } eqtn(:monthly_rate) { annual_rate / 12.0 } var :payment, 2000 eqtn :balance, 250000 do balance * (1 + monthly_rate) - payment end end

We want the period to be monthly instead of annually, so note the monthly_rate variable above. We also have various default values we will override in a bit. Let’s look at 3 types of mortgages, fixed, balloon, and variable. Fixed rate mortgages have a constant interest rate locked over a defined term (such as 30 years). Let’s see what happens to the balance at the end of 30 years for each of these loan types. A balloon loan has a lower monthly payment, but a large payment at the end of the term. A variable loan has a term where the interest rate is indexed to a published interest rate, and then a period where the rate is fixed. Below, we simplify things by assuming that we will just pay different amounts for each of the terms.

fixed = @model.new_run fixed.set payment: 2100 fixed.step 30*12 # balloon balloon = @model.new_run balloon.set payment: 1850 balloon.step 30*12 variable = @model.new_run # first 10 years, stick with low payment variable.set payment: 1800 variable.step 10*12 # subsequent years, balloon to higher payment until its paid variable.set payment: 2100 variable.step 20*12

And then we can get the series data and plot it similarly to before. It results in an image like the one below.

- Fixed = yellow
- Variable = blue
- Balloon = red

You can find the Homepage for the Simulator gem on Github and find the gem on RubyGems.