1
1
#!/usr/bin/env python
3
from __future__ import print_function
8
# supported shapes: ninth, seventh, fifth, cube, square, log
15
6
"""Calculates PWM levels for visually-linear steps.
17
# Get parameters from the user
19
(str, 'ramp_shape', 'cube', 'Ramp shape? [cube, square, fifth, seventh, ninth, log, N.NN]'),
20
(int, 'num_channels', 1, 'How many power channels?'),
21
(int, 'num_levels', 4, 'How many total levels do you want?'),
23
questions_per_channel = [
24
(str, 'type', '7135', 'Type of channel - 7135 or FET:'),
25
(int, 'pwm_min', 6, 'Lowest visible PWM level:'),
26
(float, 'lm_min', 0.25, 'How bright is the lowest level, in lumens?'),
27
#(int, 'pwm_max', max_pwm, 'Highest PWM level:'),
28
(float, 'lm_max', 1000, 'How bright is the highest level, in lumens?'),
31
def ask(questions, ans):
32
for typ, name, default, text in questions:
33
value = get_value(text, default, args)
38
setattr(ans, name, value)
41
ask(questions_main, answers)
44
ramp_shape = answers.ramp_shape
48
print('Describe the channels in order of lowest to highest power.')
49
for chan_num in range(answers.num_channels):
51
print('===== Channel %s =====' % (chan_num+1))
53
chan.pwm_max = max_pwm
54
ask(questions_per_channel, chan)
55
chan.type = chan.type.upper()
56
if chan.type not in ('7135', 'FET'):
57
raise ValueError('Invalid channel type: %s' % (chan.type,))
60
# calculate total output of all previous channels
61
for i, channel in enumerate(channels):
64
if channels[j].type == '7135':
65
channel.prev_lm += channels[j].lm_max
67
# figure out the desired PWM values
68
multi_pwm(answers, channels)
70
if interactive: # Wait on exit, in case user invoked us by clicking an icon
71
print('Press Enter to exit:')
79
def multi_pwm(answers, channels):
80
lm_min = channels[0].lm_min
81
# figure out the highest mode
82
lm_max = max([(c.lm_max+c.prev_lm) for c in channels])
83
if channels[-1].type == 'FET':
84
if channels[-1].lm_max > channels[-1].prev_lm:
85
# assume the highest output is with only the FET enabled
86
lm_max = channels[-1].lm_max
88
# this would be a stupid driver design
89
raise ValueError("FET channel isn't the most powerful?")
91
visual_min = invpower(lm_min)
92
visual_max = invpower(lm_max)
93
step_size = (visual_max - visual_min) / (answers.num_levels-1)
95
# Determine ideal lumen levels
98
for i in range(answers.num_levels):
99
goal_lm = power(goal_vis)
100
goals.append((goal_vis, goal_lm))
101
goal_vis += step_size
103
# Calculate each channel's output for each level
104
for cnum, channel in enumerate(channels):
106
for i in range(answers.num_levels):
107
goal_vis, goal_lm = goals[i]
108
# This channel already is maxed out
109
if goal_lm >= (channel.lm_max + channel.prev_lm):
110
# This shouldn't happen, the FET is assumed to be the highest channel
111
if channel.type == 'FET':
112
# this would be a stupid driver design
113
raise ValueError("FET channel isn't the most powerful?")
115
# Handle FET turbo specially
116
if (i == (answers.num_levels - 1)) \
117
and (cnum < (len(channels)-1)) \
118
and (channels[-1].type == 'FET'):
119
channel.modes.append(0.0)
120
# Normal non-turbo mode or non-FET turbo
122
channel.modes.append(channel.pwm_max)
123
# This channel's active ramp-up range
124
#elif goal_lm > (channel.prev_lm + channel.lm_min):
125
elif goal_lm > channel.prev_lm:
126
# assume 7135 channels all add together
127
if channel.type == '7135':
128
diff = channel.lm_max - channel.lm_min
129
# assume FET channel gets higher output on its own
130
elif channel.type == 'FET':
131
diff = channel.lm_max - channel.prev_lm - channel.lm_min
133
needed = goal_lm - channel.prev_lm - channel.lm_min
135
ratio = needed / diff * (channel.pwm_max-channel.pwm_min)
136
pwm = max(0, ratio + channel.pwm_min)
137
channel.modes.append(pwm)
138
# This channel isn't active yet, output too low
140
channel.modes.append(0)
142
# Show individual levels in detail
143
for i in range(answers.num_levels):
144
goal_vis, goal_lm = goals[i]
146
for channel in channels:
147
pwms.append('%.2f/%i' % (channel.modes[i], channel.pwm_max))
148
print('%i: visually %.2f (%.2f lm): %s' %
149
(i+1, goal_vis, goal_lm, ', '.join(pwms)))
151
# Show values we can paste into source code
152
for cnum, channel in enumerate(channels):
153
print('PWM%s values: %s' %
155
','.join([str(int(round(i))) for i in channel.modes])))
157
# Show highest level for each channel before next channel starts
158
for cnum, channel in enumerate(channels[:-1]):
161
while (i < answers.num_levels) \
162
and (channel.modes[i] >= channel.modes[i-1]) \
163
and (channels[cnum+1].modes[i] == 0):
165
print('Ch%i max: %i (%.2f/%s)' % (cnum, i, channel.modes[i-1], max_pwm))
168
def get_value(text, default, args):
169
"""Get input from the user, or from the command line args."""
176
print(text + ' (%s) ' % (default), end='')
177
result = input_text()
178
result = result.strip()
183
ninth = (lambda x: x**9, lambda x: math.pow(x, 1/9.0)),
184
seventh= (lambda x: x**7, lambda x: math.pow(x, 1/7.0)),
185
fifth = (lambda x: x**5, lambda x: math.pow(x, 1/5.0)),
186
cube = (lambda x: x**3, lambda x: math.pow(x, 1/3.0)),
187
square = (lambda x: x**2, lambda x: math.pow(x, 1/2.0)),
188
log = (lambda x: math.e**x, lambda x: math.log(x, math.e)),
189
# makes no difference; all logs have the same curve
190
#log_2 = (lambda x: 2.0**x, lambda x: math.log(x, 2.0)),
195
factor = float(ramp_shape)
196
return math.pow(x, factor)
198
return shapes[ramp_shape][0](x)
203
factor = float(ramp_shape)
204
return math.pow(x, 1.0 / factor)
206
return shapes[ramp_shape][1](x)
211
value = raw_input() # python2
213
value = input() # python3
8
# change these values for each device:
9
pwm_min = 0 # lowest visible PWM level, for moon mode
10
lm_min = 10.0 # how bright is moon mode, in lumens?
11
pwm_max = 255 # highest PWM level
12
lm_max = 1300 # how bright is the highest level, in lumens?
13
num_levels = 4 # how many total levels do you want?
14
# The rest should work fine without changes
15
visual_min = math.pow(lm_min, 1.0/3)
16
visual_max = math.pow(lm_max, 1.0/3)
17
step_size = (visual_max - visual_min) / (num_levels-1)
20
for i in range(num_levels):
21
pwm_float = (((goal**3) / lm_max) * (256-pwm_min)) + pwm_min - 1
22
pwm = int(round(pwm_float))
23
pwm = max(min(pwm,pwm_max),pwm_min)
25
print '%i: visually %.2f (%.2f lm): %.2f/255' % (i+1, goal, goal ** 3, pwm_float)
28
print ','.join([str(i) for i in modes])
217
30
if __name__ == "__main__":