简体   繁体   English

如何在python中实现平滑钳function?

[英]How to implement a smooth clamp function in python?

The clamp function is clamp(x, min, max) = min if x < min, max if x > max, else x clamp function 是clamp(x, min, max) = min if x < min, max if x > max, else x

I need a function that behaves like the clamp function, but is smooth (ie has a continuous derivative).我需要一个 function,它的行为类似于钳位 function,但它是平滑的(即具有连续导数)。

What you are looking for is something like the Smoothstep function, which has a free parameter N , giving the "smoothness", ie how many derivatives should be continuous.您正在寻找的是类似于Smoothstep函数的东西,它有一个自由参数N ,给出“平滑度”,即有多少导数应该是连续的。 It is defined as such:它是这样定义的:

在此处输入图片说明

This is used in several libraries and can be implemented in numpy as这在几个库中使用,可以在 numpy 中实现为

import numpy as np
from scipy.special import comb

def smoothstep(x, x_min=0, x_max=1, N=1):
    x = np.clip((x - x_min) / (x_max - x_min), 0, 1)

    result = 0
    for n in range(0, N + 1):
         result += comb(N + n, n) * comb(2 * N + 1, N - n) * (-x) ** n

    result *= x ** (N + 1)

    return result

It reduces to the regular clamp function given N=0 (0 times differentiable), and gives increasing smoothness as you increase N. You can visualize it like this:它简化为给定N=0 (0 次可微)的常规钳位函数,并随着 N 的增加提供越来越多的平滑度。您可以像这样想象它:

import matplotlib.pyplot as plt

x = np.linspace(-0.5, 1.5, 1000)

for N in range(0, 5):
    y = smoothstep(x, N=N)
    plt.plot(x, y, label=str(N))

plt.legend()

which gives this result:这给出了这个结果:

在此处输入图片说明

Normal clamp:普通夹具:

np.clip(x, mi, mx)

Smoothclamp (guaranteed to agree with normal clamp for x < min and x > max): Smoothclamp(保证在 x < min 和 x > max 时与正常夹具一致):

def smoothclamp(x, mi, mx): return mi + (mx-mi)*(lambda t: np.where(t < 0 , 0, np.where( t <= 1 , 3*t**2-2*t**3, 1 ) ) )( (x-mi)/(mx-mi) )

Sigmoid (Approximates clamp, never smaller than min, never larger than max) Sigmoid(近似钳位,从不小于最小值,从不大于最大值)

def sigmoid(x,mi, mx): return mi + (mx-mi)*(lambda t: (1+200**(-t+0.5))**(-1) )( (x-mi)/(mx-mi) )

For some purposes Sigmoid will be better than Smoothclamp because Sigmoid is an invertible function - no information is lost.出于某些目的,Sigmoid 会比 Smoothclamp 更好,因为 Sigmoid 是一个可逆函数——不会丢失任何信息。

For other purposes, you may need to be certain that f(x) = xmax for all x > xmax - in that case Smoothclamp is better.出于其他目的,您可能需要确定f(x) = xmax对于所有x > xmax - 在这种情况下 Smoothclamp 更好。 Also, as mentioned in another answer, there is a whole family of Smoothclamp functions, though the one given here is adequate for my purposes (no special properties other than a smooth derivative needed)此外,正如在另一个答案中提到的,有一整套 Smoothclamp 函数,尽管这里给出的函数足以满足我的目的(除了需要平滑导数之外,没有其他特殊属性)

Plot them:绘制它们:

import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
x = np.linspace(-4,7,1000)
ax.plot(x, np.clip(x, -1, 4),'k-', lw=2, alpha=0.8, label='clamp')
ax.plot(x, smoothclamp(x, -1, 4),'g-', lw=3, alpha=0.5, label='smoothclamp')
ax.plot(x, sigmoid(x, -1, 4),'b-', lw=3, alpha=0.5, label='sigmoid')
plt.legend(loc='upper left')
plt.show()

图形

Also of potential use is the arithmetic mean of these two:同样具有潜在用途的是这两者的算术平均值:

def clampoid(x, mi, mx): return mi + (mx-mi)*(lambda t: 0.5*(1+200**(-t+0.5))**(-1) + 0.5*np.where(t < 0 , 0, np.where( t <= 1 , 3*t**2-2*t**3, 1 ) ) )( (x-mi)/(mx-mi) )

As an option, if you want to make sure that there is a correspondence with the clamp function, you can convolve the normal clamp function with a smooth bell-like function such as Lorentzian or Gaussian.作为一种选择,如果您想确保与钳位 function 存在对应关系,您可以将普通钳位 function 与光滑的钟状 function(例如洛伦兹或高斯)进行卷积。

This will guarantee the correspondence between the normal clamp function and its smoothed version.这将保证正常夹具 function 与其平滑版本之间的对应关系。 The smoothness itself will be defined by the underlying smooth function you choose to use in the convolution.平滑度本身将由您选择在卷积中使用的底层平滑度 function 定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM