1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
#!/usr/bin/env python
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 = [
(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?'),
#(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)
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.'
def get_value(text, default, args):
"""Get input from the user, or from the command line args."""
if args:
result = args[0]
del args[0]
else:
global interactive
interactive = True
print text, '(%s)' % (default),
result = raw_input()
result = result.strip()
return result
def power(x):
#return x**5
return x**3
#return x**2
#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)
#return math.pow(x, 1/2.0)
#return math.log(x, math.e)
#return math.log(x, 2.0)
if __name__ == "__main__":
import sys
main(sys.argv[1:])
|