aboutsummaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorSelene ToyKeeper2016-05-22 18:42:01 -0600
committerSelene ToyKeeper2016-05-22 18:42:01 -0600
commit4b794fa1566ed670e185f4045472ad75406c2a9a (patch)
tree0200a9c7b868f7f47d01bd51a8a07a7525685c5d /bin
parentDifferent tiny25 fuses: No brownout detection, and slower startup. (diff)
downloadanduril-4b794fa1566ed670e185f4045472ad75406c2a9a.tar.gz
anduril-4b794fa1566ed670e185f4045472ad75406c2a9a.tar.bz2
anduril-4b794fa1566ed670e185f4045472ad75406c2a9a.zip
Made level_calc.py work with any number of power channels.
Results are slightly different than before, and I'm not sure if I broke something or fixed something. Hard to tell. Regardless, it seems to work fine.
Diffstat (limited to '')
-rwxr-xr-xbin/level_calc.py192
1 files changed, 96 insertions, 96 deletions
diff --git a/bin/level_calc.py b/bin/level_calc.py
index 63926ba..6a82563 100755
--- a/bin/level_calc.py
+++ b/bin/level_calc.py
@@ -4,115 +4,112 @@ import math
interactive = False
+
def main(args):
"""Calculates PWM levels for visually-linear steps.
"""
# Get parameters from the user
- v = dict(pwm_max=255, pwm2_max=255)
- questions = [
+ questions_main = [
+ (int, 'num_channels', 1, 'How many power channels?'),
(int, 'num_levels', 4, 'How many total levels do you want?'),
- (int, 'pwm_min', 6, 'Lowest visible PWM level, for moon mode:'),
- (float, 'lm_min', 0.25, 'How bright is moon mode, in lumens?'),
+ ]
+ questions_per_channel = [
+ (int, 'pwm_min', 6, 'Lowest visible PWM level:'),
+ (float, 'lm_min', 0.25, 'How bright is the lowest level, in lumens?'),
#(int, 'pwm_max', 255, 'Highest PWM level:'),
(float, 'lm_max', 1000, 'How bright is the highest level, in lumens?'),
- (str, 'dual_pwm', 'n', 'Use dual PWM? [y/n]'),
- (float, 'pwm2_min', 6, 'Second channel, lowest visible PWM level:'),
- (float, 'lm2_min', 0.25, 'Second channel, how bright is the lowest mode, in lumens?'),
- #(float, 'pwm2_max', 255, 'Second channel, highest PWM level:'),
- (float, 'lm2_max', 140, 'Second channel, how bright is maximum, in lumens?'),
]
- for typ, name, default, text in questions:
- value = get_value(text, default, args)
- if not value:
- value = default
- else:
- value = typ(value)
- v[name] = value
- if (name == 'dual_pwm' and value == 'n'):
- # skip remaining questions if not using dual PWM
- break
-
- if v['dual_pwm'] == 'y':
- dual_pwm(v)
- else:
- single_pwm(v)
+
+ def ask(questions, ans):
+ for typ, name, default, text in questions:
+ value = get_value(text, default, args)
+ if not value:
+ value = default
+ else:
+ value = typ(value)
+ setattr(ans, name, value)
+
+ answers = Empty()
+ ask(questions_main, answers)
+ channels = []
+ if not args:
+ print('Describe the channels in order of lowest to highest power.')
+ for chan_num in range(answers.num_channels):
+ if not args:
+ print('===== Channel %s =====' % (chan_num+1))
+ chan = Empty()
+ chan.pwm_max = 255
+ ask(questions_per_channel, chan)
+ channels.append(chan)
+
+ multi_pwm(answers, channels)
if interactive: # Wait on exit, in case user invoked us by clicking an icon
print 'Press Enter to exit:'
raw_input()
-def single_pwm(v):
- """Estimate the PWM levels for a one-channel driver."""
- visual_min = invpower(v['lm_min'])
- visual_max = invpower(v['lm_max'])
- step_size = (visual_max - visual_min) / (v['num_levels']-1)
- modes = []
- goal = visual_min
- for i in range(v['num_levels']):
- goal_lm = power(goal)
- #pwm_float = ((goal_lm / v['lm_max']) * (256-v['pwm_min'])) + v['pwm_min'] - 1
- pwm_float = (((goal_lm-v['lm_min']) / (v['lm_max']-v['lm_min'])) \
- * (255-v['pwm_min'])) \
- + v['pwm_min']
- pwm = int(round(pwm_float))
- pwm = max(min(pwm,v['pwm_max']),v['pwm_min'])
- modes.append(pwm)
- print '%i: visually %.2f (%.2f lm): %.2f/255' % (i+1, goal, goal_lm, pwm_float)
- goal += step_size
-
- print 'PWM values:', ','.join([str(i) for i in modes])
-
-def dual_pwm(v):
- """Estimate the PWM levels for a two-channel driver.
- Assume the first channel is the brighter one, and second will be used for moon/low modes.
- """
- #visual_min = math.pow(v['lm2_min'], 1.0/power)
- #visual_max = math.pow(v['lm_max'], 1.0/power)
- visual_min = invpower(v['lm2_min'])
- visual_max = invpower(v['lm_max'])
- step_size = (visual_max - visual_min) / (v['num_levels']-1)
- modes = []
- goal = visual_min
- for i in range(v['num_levels']):
- goal_lm = power(goal)
- # Up to the second channel's limit, calculate things just like a
- # single-channel driver (first channel will be zero)
- if goal_lm <= v['lm2_max']:
- pwm1_float = 0.0
- #pwm2_float = ((goal_lm / v['lm2_max']) * (256-v['pwm2_min'])) + v['pwm2_min'] - 1
- pwm2_float = (((goal_lm-v['lm2_min']) / (v['lm2_max']-v['lm2_min'])) \
- * (255-v['pwm2_min'])) \
- + v['pwm2_min']
- pwm1 = int(round(pwm1_float))
- pwm2 = int(round(pwm2_float))
- pwm2 = max(min(pwm2,v['pwm2_max']),v['pwm2_min'])
- modes.append((int(pwm1),int(pwm2)))
- # Above the second channel's limit, things get a little more
- # complicated (second channel will be 255, first channel will be
- # adjusted down by the max output of the second channel)
- else:
- if len(modes) == v['num_levels'] -1: # turbo is special
- #pwm1_float = ((goal_lm / v['lm_max']) * (256-v['pwm_min'])) + v['pwm_min'] - 1
- pwm1_float = float(v['pwm_max'])
- # on a FET+7135 driver, turbo works better without the 7135
- # (we're assuming FET+7135 here)
- pwm2_float = 0.0
- else: # not the highest mode yet
- #pwm1_float = (((goal_lm-v['lm2_max']) / v['lm_max']) * (256-v['pwm_min'])) + v['pwm_min'] - 1
- pwm1_float = (((goal_lm-v['lm_min']-v['lm2_max']) / (v['lm_max']-v['lm_min'])) \
- * (255-v['pwm_min'])) \
- + v['pwm_min']
- pwm2_float = 255.0
- pwm1 = int(round(pwm1_float))
- pwm2 = int(round(pwm2_float))
- pwm1 = max(min(pwm1,v['pwm_max']),v['pwm_min'])
- modes.append((int(pwm1),int(pwm2)))
- print '%i: visually %.2f (%.2f lm): %.2f/255, %.2f/255' % (i+1, goal, goal_lm, pwm1_float, pwm2_float)
- goal += step_size
-
- print 'PWM1/FET values:', ','.join([str(i[0]) for i in modes])
- print 'PWM2/7135 values:', ','.join([str(i[1]) for i in modes])
- print 'On a non-FET driver, the last mode should be 255 on both channels.'
+
+class Empty:
+ pass
+
+
+def multi_pwm(answers, channels):
+ lm_min = channels[0].lm_min
+ lm_max = channels[-1].lm_max
+ visual_min = invpower(lm_min)
+ visual_max = invpower(lm_max)
+ step_size = (visual_max - visual_min) / (answers.num_levels-1)
+
+ # Determine ideal lumen levels
+ goals = []
+ goal_vis = visual_min
+ for i in range(answers.num_levels):
+ goal_lm = power(goal_vis)
+ goals.append((goal_vis, goal_lm))
+ goal_vis += step_size
+
+ # Calculate each channel's output for each level
+ for cnum, channel in enumerate(channels):
+ prev_channel = Empty() ; prev_channel.lm_max = 0.0
+ if cnum > 0:
+ prev_channel = channels[cnum-1]
+ channel.modes = []
+ for i in range(answers.num_levels):
+ goal_vis, goal_lm = goals[i]
+ # This channel already is maxed out
+ if goal_lm >= channel.lm_max:
+ # Handle turbo specially, enable only biggest channel
+ if (i == (answers.num_levels - 1)) and (cnum < (len(channels)-1)):
+ channel.modes.append(0.0)
+ else:
+ channel.modes.append(channel.pwm_max)
+ # This channel's active ramp-up range
+ elif goal_lm > prev_channel.lm_max:
+ # FIXME: This produces somewhat different values than the
+ # dual_pwm() algorithm, and I'm not sure which one is "right"
+ diff = channel.lm_max - prev_channel.lm_max
+ needed = goal_lm - prev_channel.lm_max
+ ratio = needed / diff * (channel.pwm_max-channel.pwm_min)
+ channel.modes.append(ratio + channel.pwm_min)
+ # This channel isn't active yet, output too low
+ else:
+ channel.modes.append(0)
+
+ # Show individual levels in detail
+ for i in range(answers.num_levels):
+ goal_vis, goal_lm = goals[i]
+ pwms = []
+ for channel in channels:
+ pwms.append('%.2f/%i' % (channel.modes[i], channel.pwm_max))
+ print('%i: visually %.2f (%.2f lm): %s' %
+ (i+1, goal_vis, goal_lm, ', '.join(pwms)))
+
+ # Show values we can paste into source code
+ for cnum, channel in enumerate(channels):
+ print('PWM%s values: %s' %
+ (cnum+1,
+ ','.join([str(int(round(i))) for i in channel.modes])))
+
def get_value(text, default, args):
"""Get input from the user, or from the command line args."""
@@ -127,6 +124,7 @@ def get_value(text, default, args):
result = result.strip()
return result
+
def power(x):
#return x**5
return x**3
@@ -134,6 +132,7 @@ def power(x):
#return math.e**x
#return 2.0**x
+
def invpower(x):
#return math.pow(x, 1/5.0)
return math.pow(x, 1/3.0)
@@ -141,6 +140,7 @@ def invpower(x):
#return math.log(x, math.e)
#return math.log(x, 2.0)
+
if __name__ == "__main__":
import sys
main(sys.argv[1:])
If you find this content useful please consider a small donation via bitcoin: bitcoin:1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2?amount=0.001&message=Donation Scraping git contents via cgit is very resource intensive. The continued hosting of these git repositories is entirely financed by your bitcoin contributions. For donations of a least 1 mBTC you include your IP address in the message of your bitcoin donation. This will remove this message in the future for requests from your IP, which will significantly reduce token usage. In any case, any contributions to bitcoin address 1mxKyQsHHugqRxPKgwaA7wUwJEGCNthn2 are very welcome. Thanks in advance for you contribution to a self-sustaining ecosystem.