Created
July 30, 2015 13:06
-
-
Save gamesbook/32c58651047a15f66a06 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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