Skip to content

Instantly share code, notes, and snippets.

@gamesbook
Created July 30, 2015 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gamesbook/32c58651047a15f66a06 to your computer and use it in GitHub Desktop.
Save gamesbook/32c58651047a15f66a06 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generate a value that occurs within a periodic cycle.
@author: dhohls@csir.co.za
"""
import numpy as np
import random
class Simulator(object):
def simulate(self, x, fn, **kwargs):
"""Generate a value from a ranged function; modified by various kwargs.
Args:
x (int): 0 to 360
fn (string): the type of function; one of:
[direct, sin, cosine]
kwargs (key,value pairs):
modifiers for the resulting value
Returns:
y (float)
"""
y = None
lower, upper, offset, delta, flat, base = 0, 1, 0, 0, False, None
# process input parameters
for key in kwargs:
#print "keyword arg: %s: %s" % (key, kwargs[key])
if key == 'variation':
try:
upper = kwargs[key].get('upper', 1)
except:
pass
try:
lower = kwargs[key].get('lower', 0)
except:
pass
try:
base = kwargs[key].get('base', None)
except:
pass
elif key == 'variance':
gain, loss = 0, 0
try:
gain = kwargs[key].get('gain', 0)
except:
pass
try:
loss = kwargs[key].get('loss', 0)
except:
pass
try:
offset = random.randint(-1 * loss, gain)
except:
pass
elif key == 'spikes':
spike_list = []
try:
spikes = kwargs[key]
for spike in spikes:
start, end, gain, loss = 0, 0, 0, 0
try:
start = spike.get('start', 0)
except:
pass
try:
end = spike.get('end', 0)
except:
pass
try:
gain = spike.get('gain', 0)
except:
pass
try:
loss = spike.get('loss', 0)
except:
pass
if x >= start and x <= end:
delta = random.randint(-1 * loss, gain)
except:
pass
elif key == 'flatten':
flats = kwargs[key]
for f in flats:
start, end, flatten = 0, 0, 100
try:
start = f.get('start', 0)
except:
pass
try:
end = f.get('end', 0)
except:
pass
try:
percent = f.get('amount', 100)
except:
pass
if x >= start and x <= end:
try:
reduction = float(percent) / 100.0
flat = True
except:
raise TypeError(
"Incorrectly formatted flatten amount: '%s'" % percent)
elif key == 'times':
_max, interval = None, None
try:
period = kwargs[key].get('period', 'day')
if period == 'day':
_max = 24 * 60 * 60
elif period == 'week':
_max = 7 * 24 * 60 * 60
else:
raise TypeError("Unknown period: '%s'" % period)
except:
pass
try:
interval = kwargs[key].get('interval', 3600) # default = 1 hour
try:
interval = float(interval)
except:
raise TypeError("Incorrectly formatted interval: '%s'" % interval)
except:
pass
# convert `x` to a degree
if _max and interval:
pass
else:
raise TypeError("Unknown key: '%s'" % key)
_range = upper - lower
# perform calculation
if fn == 'direct':
y = x
elif fn == 'sine':
y = np.sin(np.radians(x)) * _range + upper + offset + delta
elif fn == 'cosine':
y = np.cosine(np.radians(x)) * _range + upper + offset + delta
else:
raise TypeError("Unknown function: '%s'" % fn)
# adjust final value
if flat:
y = y - y * reduction
if base:
y = max(y, base)
return y
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Test the Simulator.
@author: dhohls@csir.co.za
"""
from datetime import datetime
from simulator import Simulator
SECONDS_PER_DAY = 84600.0
DEBUG = False
def get_daily_sim(_date, interval=600, **kwargs):
""""Extract a simulated value for a single time during one day.
Call this method in a loop that iterates over a datetime range.
Args:
_date: datetime object
the actual start of the simulation range
interval: int
seconds between each value
kwargs:
various parameters to control wave form (see code)
Note:
360 degrees (for waveform) == 1 day
"""
upper = kwargs.get('upper', 250)
lower = kwargs.get('lower', 50)
gain = kwargs.get('gain', 40)
loss = kwargs.get('loss', 20)
spikes = kwargs.get('spikes', None)
flatten = kwargs.get('flatten', None)
current_sec = float(_date.hour * 60 * 60 + _date.minute * 60 + _date.second)
step = current_sec / SECONDS_PER_DAY * 360.0 # convert to degrees: 0 to 360
step = step - 90 if step >= 90 else step + 270 # phase shift by 90
# spike values specified in degrees!
spikes = spikes or \
[{'start': 50, 'end': 80, 'gain': 60, 'loss': 10},
{'start': 120, 'end': 140, 'gain': 80, 'loss': 5},
{'start': 250, 'end': 320, 'gain': 0, 'loss': 50}]
times = {'period': 'day', 'interval': interval} # interval in seconds
variation = {'upper': upper, 'lower': lower, 'base': 0}
variance = {'gain': gain, 'loss': loss}
# flatten values specified as a percentage!
flatten = flatten or \
[{'start': 180, 'end': 240, 'amount': 50},
{'start': 240, 'end': 320, 'amount': 80},
{'start': 320, 'end': 360, 'amount': 70},
{'start': 0, 'end': 20, 'amount': 80},]
out = self.simulator.simulate(
step, 'sine', variation=variation, times=times, spikes=spikes,
variance=variance, flatten=flatten)
return out
#_date = datetime.now()
#get_daily_sim(_date, interval=600)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment