似乎是一个简单的图形问题

3
目前,我有一个控件需要添加各种锐度(或灵敏度)的功能。最好通过以下图片进行说明: Graph http://img87.imageshack.us/img87/7886/control.png 如您所见,我有X和Y轴,它们都有任意的100个限制-这应该足以解释。目前,我的控件是红线(线性行为),但我想添加其他3条曲线(或更多)。即,如果控件更灵敏,则设置将忽略线性设置并选择三条曲线之一。起点始终为0,终点始终为100。
我知道指数太陡峭,但似乎找不到前进的方式。请您有什么建议吗?

为什么加上C#标签?虽然您的解决方案最终可能是C#,但我在问题中看不出任何与C#有关的内容。因此将去除该标签... - abelenky
请解释您想要的行为(除起点/终点之外)。这是指数形式的吗?多项式形式的?对数形式的?看起来在0附近的斜率是线性的,然后根据需要向上缩放以满足终点。 - Jason S
...或者是线性和某种插值的结合。 - Jason S
为了方便其他浏览该网站的人,您可能想将标题更改为类似于“用于调整灵敏度的好数学函数是什么?”之类的内容。如果问题确实得到解答,请将其标记为已回答。 :) - Paul Hooper
6个回答

3
您所描绘的曲线很像伽玛校正曲线。其想法是,范围的最小值和最大值保持与输入相同,但中间部分被弯曲,就像你在图表中所示的一样(我要注意的是,这并不是从余弦实现中得到的圆弧)。
以图形方式表示,如下所示: alt text (来源: wikimedia.org
因此,以此为灵感,以下是数学公式...
如果您的x值范围从0到1,则该函数非常简单:
y = f(x, gamma) = x ^ gamma

添加一个xmax值用于缩放(例如x = 0到100),函数变为:

y = f(x, gamma) = ((x / xmax) ^ gamma) * xmax

或者,另一种选择是:
y = f(x, gamma) = (x ^ gamma) / (xmax ^ (gamma - 1))

如果您想添加非零的xmin,可以进一步操作。当gamma为1时,该线始终完全线性(y = x)。如果x小于1,则曲线向上弯曲。如果x大于1,则曲线向下弯曲。gamma的倒数值将将该值转换回原始值(x = f(y,1 / g)= f(f(x,g),1 / g))。根据自己的口味和应用需求调整gamma的值即可。因为您想要为用户提供多个“灵敏度增强”选项,所以您可能希望在线性刻度上为用户提供选择,例如从-4(最不敏感)到0(无变化)到4(最敏感),并使用幂函数缩放内部gamma值。换句话说,让用户选择(-4、-3、-2、-1、0、1、2、3、4),但将其转换为gamma值(5.06、3.38、2.25、1.50、1.00、0.67、0.44、0.30、0.20)。在C#中编写代码可能如下所示:
public class SensitivityAdjuster {
    public SensitivityAdjuster() { }
    public SensitivityAdjuster(int level) {
        SetSensitivityLevel(level);
    }
    private double _Gamma = 1.0;
    public void SetSensitivityLevel(int level) {
        _Gamma = Math.Pow(1.5, level);
    }
    public double Adjust(double x) {
        return (Math.Pow((x / 100), _Gamma) * 100);
    }
}

要使用它,创建一个新的SensitivityAdjuster,根据用户偏好设置灵敏度级别(可以使用构造函数或方法,-4到4可能是合理的级别值),然后调用Adjust(x)以获取调整后的输出值。如果您想要更宽或更窄的合理级别范围,则可以在SetSensitivityLevels方法中减少或增加1.5的值。当然,100代表您的最大x值。

这是我的解决方案(至少对我来说是这样)。我尝试了这个方法,它实现了我需要的一切。Paul,我无法感谢你,我一直像只“追逐自己尾巴”的狗一样在这个问题上纠结。再次感谢! - user68528

1

我提出一个简单的公式,(我相信)可以满足您的需求。为了得到一个完整的“四分之一圆形”,这是您的极端情况,您可以使用(1-cos((x*pi)/(2*100)))*100

我建议您在y=x和y=(1-cos((x*pi)/(2*100)))*100之间取加权平均值。例如,要非常接近于线性(99%线性),请使用:

y = 0.99*x + 0.01*[(1-cos((x*pi)/(2*100)))*100]

更一般地说,假设线性程度为L,且在区间[0,1]内,则您的公式将为:

y = L*x + (1-L)*[(1-cos((x*pi)/(2*100)))*100]

编辑:我将cos(x/100)更改为cos((x*pi)/(2*100)),因为为了使cos结果在[1,0]范围内,X应该在[0,pi/2]范围内而不是[0,1],对于最初的错误表示抱歉。


我喜欢简单的公式。明天我一定会尝试这个。非常感谢! - user68528

0

我支持Rax Olgud的总体想法,但有一个修改:

y = alpha * x + (1-alpha)*(f(x/100)*100)

alt text http://www4c.wolframalpha.com/Calculate/MSP/MSP4501967d41e1aga1b3i00004bdeci2b6be2a59b?MSPStoreType=image/gif&s=6

其中f(0) = 0,f(1) = 1,f(x)是超线性的,但我不知道这个“四分之一圆”想法来自哪里,或者为什么1-cos(x)会是一个好选择。

我建议使用f(x) = xk,其中k = 2、3、4、5,无论α等于多少,都可以给您所需的陡峭程度。选择一个固定的k值,然后变化α以选择您特定的曲线。


我相信Rax Olgud选择了四分之一圆和一个圆形函数,因为圆形函数在靠近一个轴时移动得比较慢,在靠近另一个轴时移动得最快。 - Nosredna

0
你可能正在寻找类似于多项式插值的东西。二次/三次/四次插值应该能够给你展示在问题中的曲线类型。你展示的三种曲线之间的差异可能只需通过调整系数(间接决定陡峭程度)来实现。

我已经看过了插值,就像曲线拟合一样,这是一个你试图将几个或更多离散点联系在一起的情况。然后使用m = x变化量/ y变化量来区分。我的情况很简单,我要么允许用户输入一个变量,要么从包含陡峭、平均和温和(我知道这些名字很糟糕)的枚举中选择,以允许他们选择曲线的陡峭程度,就像关闭汽车牵引控制一样,并且不进行插值,因为目前没有点。我需要生成它们。 - user68528
谢谢,我会尝试这个和AakashM的建议。 - user68528

0

当你从1开始变化p时,x从0到1的y = x^p图将会做你想要的事情(这将给出红线)。随着p的增加,曲线将被越来越“推入”。p不必是整数。

(你需要进行缩放以获得0到100,但我相信你可以解决这个问题)


x^p,其中p>1,在0附近给出斜率为0。这看起来不像你绘制的曲线。 - Jason S

0
对于这样的问题,我通常会从曲线上获取几个点,并将其通过曲线拟合程序进行处理。市面上有很多这样的程序。这里有一个带有7天免费试用的程序。 尝试不同的模型可以让我学到很多东西。通常情况下,你可以得到一个相当简单的表达式来接近你的曲线。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接