我有一个滑块,可用于更改可以具有宽范围值的参数(y
)。滑块的位置以整数(x
)表示。
我的参数保存一个源的能量,并且可以具有从0.1 nJ一直到10 J的值。出于应用目的,我希望参数步长为:
我正在尝试通过使用整数除法(x => y
和余数(//
)来转换这些值(%
),但是遇到问题时遇到了问题例如,从一个子范围跨越到另一个子范围。
x = 9999给出y = 999.9 nJ,但是x = 10000给出y = 0.0 µJ,因此在系统中为0,远低于999.9 nJ。下一步(x = 10001)得到y = 0.1 µJ,也低于999.9 nJ。
理想情况下,y的步长应为999.9 nJ-1.0 µJ-1.1 µJ。
此MWE使用key detection来读取键的输入,而不必按Enter。
import math as m
import sys, termios, tty, os, time
prefixes = {-18:'a', -15:'f', -12:'p', -9:'n', # Prefixes for displaying the value
-6:'\u03bc', -3:'m', #-2:'c', -1:'d',
+0:'', #+1:'da', +2:'h',
+3:'k', +6:'M', +9:'G', +12:'T', +15:'P', +18:'E'}
def getch(): # Get character from keyboard without waiting for enter
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def calcy(): # Convert from x integer to y value for display
print("x: " + repr(x))
exp2 = 3*((x/resolution) // 1e+3) + exp0 # integer division
yp2 = round((x/resolution)%(1e+3), digits) # remainder
y2 = round(yp2 * m.pow(10, exp2), int(digits-exp2))
print("y: " + repr(y2) + " equal to " + repr(yp2) + str(prefixes[exp2]) + "J\n")
button_delay = 0.1
y = float(input("Give starting value:")) # Choose a value to start from
exp0 = -9 # Exponent of minimum range [nJ]
digits = 1 # Number of decimals to be used
resolution = m.pow(10, 1) # The number of points for a change of size 1
exp = 0 # Exponent of y
yp = y # Short number of y
while yp < 1/resolution: # While the number is not in the prefixed unit
yp = yp*1e+03 # Multiply yp by 1000 (10³)
exp -= 3 # Exponent increases by 3
yp = round(y * m.pow(10, -exp), digits) # The display value
x = int((yp + (exp - exp0)/3 * 1e+3) * resolution) # Integer value representing the silder value
calcy() # Calculate y from x integer
while True:
char = getch() # Get pressed key
if char == 'q': # If it was q, quit
exit(0)
elif char == '+': # If it was +, increase x by one and
x += 1 # recalculate y
calcy()
time.sleep(button_delay)
elif char == '-': # If it was -, decrease x by one and
x -= 1 # recalculate y
calcy()
time.sleep(button_delay)
else:
print(char)
time.sleep(button_delay)
如果您想尝试该程序,建议您以500e-9
作为起始值,并按6次-
以达到y = 999.9 nJ,因为这是问题所在。
我知道使用我使用的算法将x = 10001转换为0.1 µJ是合乎逻辑的,但我不知道如何解决。如果您只能使用+
和-
按钮更改值,则可以直接从9999转到10011,这在逻辑上将y = 1.1 µJ,但是我将如何处理实际可以用鼠标拖动滑块吗?
请给我您如何解决此问题的想法。
答案 0 :(得分:1)
在每个半开间隔中都有9999个值,而在上一个关闭间隔中有90个值,因为(例如)10000(0.1nJ)= 1 µJ。这使转换变得容易:
def val(x): # 0<=x<30,087
r,x=divmod(x,9999)
return (x+1)*1000**(r-3)/10
(评论中有一些内容涉及扩展以支持其他范围,但还不够具体,无法回答。)
答案 1 :(得分:0)
由于@ Davis-Herring的评论和建议,我想我已经解决了。现在可以针对不同的分辨率(步长)和起始指数(exp0)调整该功能。
def calcy(x):
if x < (1000*resolution - 1): # The number of values from the start to the first prefix change
exp = exp0
yp = round((x + 1)/resolution, digits) # Round to account for numerical discrepancies
else:
n = round((1000 - 1) * resolution) # The number of values in all other ranges
z = round(x - (1000 * resolution - 1)) # Subtract the number of values in the first range
r = z // n + 1 # The number of passed ranges
yp = round((z % n)/resolution + 1, digits)
exp = exp0 + 3 * r
return yp * 10**exp
在resolution = 10
和digits = 1
中,第一范围内的每一步为0.1 nJ,然后为0.1 µJ,0.1mJ ......