动态改变频率时使振荡平滑increase/decrease
Make oscillations smoothly increase/decrease when frequency being changed dynamically
我正在用 html5 canvas 模拟共振效果,以便在达到共振时为 spring 设置动画。
还获得了 jquery ui 滑块(最大范围),可在动画期间动态更改振荡频率 (w)。问题是当它发生变化时,由于某种原因正弦波在某些点中断并且动画不流畅。这只发生在改变频率时,幅度要好得多。
我渲染每一帧的主要功能是:
function doSways() {
var spring = springs[0],
a = 0,
A = params.standParams.A,
w = params.standParams.w;
animIntervalId = setInterval(function() {
ctx.clearRect(0, 0, cnvW, cnvH);
A = params.standParams.A;
w = params.standParams.w;
/*if (w < params.standParams.w) { // with this expression and commented <w = params.standParams.w> it works a bit smoother but still some issues can be noticed, for example sharp increases just after the new change of the frequency (w) on the slider
w += 0.01;
}*/
stand.y = A*Math.sin(a*degToRad*w) + offsetY;
stand.draw();
spring.draw(stand.y, A, w);
if (a++ >= 360) { // avoid overflow
a = 0;
}
},
25);
}
这是我如何更改滑块上的频率 (w) 并将其分配给 params.standParams.w
$( "#standfreq_slider" ).slider({
range: "max",
min: 1,
max: 25,
step: 1,
value: 5,
slide: function( event, ui ) {
params.standParams.w = parseInt(ui.value);
}
});
);
如果 doSways 函数中的表达式有点工作但它会导致另一个问题,我需要知道滑动的方向以确定我是否需要 += 或 -= 0.01..
如何让一切都完美运行?
现场问题说明
jsfiddle
好吧,我在下面解释的模式是我经常使用的模式。
(它很可能有一个名字 - 请 S.O。如果有,请告诉我。)
思路是这样的:每当你想要一个属性平稳发展的时候,你必须区分target值,和当前 值。如果由于某种原因 target 值发生变化,它只会影响您决定的 current 值。
要从当前值到目标值,你有很多方法:
• 最简单:只需在每次报价时使其更接近给定比率:
current += ratio * (target-current);
其中比率在 [0, 1] 范围内,0.1 可能没问题。您会看到,比率 == 1,当前 == 目标在第一次滴答时。
请注意,此解决方案依赖于帧速率,并且您可能希望对值进行阈值处理以在某个时候获得完全相同的值,expl :
var threshold = 0.01 ;
if (Math.abs(target-current)<threshold) current = target;
• 您也可以以给定的速度到达目标:
var sign = (target - current) > 0 ? 1 : -1;
current += sign * speedToReachTarget * dt;
现在我们不依赖于帧速率(您必须正确处理帧时间),但如果您不应用 min/max 和阈值,您将有 'bouncing':
if (Math.abs(target-current)<0.01) {
current = target;
return;
}
var sign = (target - current) > 0 ? 1 : -1;
current += sign * speedToReachTarget * dt;
current = (( sign > 0) ? Math.min : Math.max )( target, current);
• 您可能会使用许多其他类型的 interpolation/easing。
基于正弦波的基本公式:
V = V0 + A * sin(2 * pi * f * t + phi)
其中:
- V:当前值
- V0:中心值
- A:振幅
- f: 频率 (Hz)
- t: 时间(秒)
- phi: 相位
我们希望电流值(V)在频率变化前后相同。为此,我们需要更改前后的频率 (f) 和相位 (phi)。
首先我们可以设置第一个等式等于第二个:
V0 + A * sin(2 * pi * f1 * t + phi1) = V0 + A * sin(2 * pi * f2 * t + phi2)
做一些取消:
2 * pi * f1 * t + phi1 = 2 * pi * f2 * t + phi2
求解最终公式的新阶段:
phi2 = 2 * pi * t * (f1 - f2) + phi1
更多数学版本:
已编辑:
签出修改 fiddle:https://jsfiddle.net/potterjm/qy1s8395/1/
我正在用 html5 canvas 模拟共振效果,以便在达到共振时为 spring 设置动画。 还获得了 jquery ui 滑块(最大范围),可在动画期间动态更改振荡频率 (w)。问题是当它发生变化时,由于某种原因正弦波在某些点中断并且动画不流畅。这只发生在改变频率时,幅度要好得多。 我渲染每一帧的主要功能是:
function doSways() {
var spring = springs[0],
a = 0,
A = params.standParams.A,
w = params.standParams.w;
animIntervalId = setInterval(function() {
ctx.clearRect(0, 0, cnvW, cnvH);
A = params.standParams.A;
w = params.standParams.w;
/*if (w < params.standParams.w) { // with this expression and commented <w = params.standParams.w> it works a bit smoother but still some issues can be noticed, for example sharp increases just after the new change of the frequency (w) on the slider
w += 0.01;
}*/
stand.y = A*Math.sin(a*degToRad*w) + offsetY;
stand.draw();
spring.draw(stand.y, A, w);
if (a++ >= 360) { // avoid overflow
a = 0;
}
},
25);
}
这是我如何更改滑块上的频率 (w) 并将其分配给 params.standParams.w
$( "#standfreq_slider" ).slider({
range: "max",
min: 1,
max: 25,
step: 1,
value: 5,
slide: function( event, ui ) {
params.standParams.w = parseInt(ui.value);
}
});
);
如果 doSways 函数中的表达式有点工作但它会导致另一个问题,我需要知道滑动的方向以确定我是否需要 += 或 -= 0.01.. 如何让一切都完美运行?
现场问题说明 jsfiddle
好吧,我在下面解释的模式是我经常使用的模式。
(它很可能有一个名字 - 请 S.O。如果有,请告诉我。)
思路是这样的:每当你想要一个属性平稳发展的时候,你必须区分target值,和当前 值。如果由于某种原因 target 值发生变化,它只会影响您决定的 current 值。
要从当前值到目标值,你有很多方法:
• 最简单:只需在每次报价时使其更接近给定比率:
current += ratio * (target-current);
其中比率在 [0, 1] 范围内,0.1 可能没问题。您会看到,比率 == 1,当前 == 目标在第一次滴答时。
请注意,此解决方案依赖于帧速率,并且您可能希望对值进行阈值处理以在某个时候获得完全相同的值,expl :
var threshold = 0.01 ;
if (Math.abs(target-current)<threshold) current = target;
• 您也可以以给定的速度到达目标:
var sign = (target - current) > 0 ? 1 : -1;
current += sign * speedToReachTarget * dt;
现在我们不依赖于帧速率(您必须正确处理帧时间),但如果您不应用 min/max 和阈值,您将有 'bouncing':
if (Math.abs(target-current)<0.01) {
current = target;
return;
}
var sign = (target - current) > 0 ? 1 : -1;
current += sign * speedToReachTarget * dt;
current = (( sign > 0) ? Math.min : Math.max )( target, current);
• 您可能会使用许多其他类型的 interpolation/easing。
基于正弦波的基本公式:
V = V0 + A * sin(2 * pi * f * t + phi)
其中:
- V:当前值
- V0:中心值
- A:振幅
- f: 频率 (Hz)
- t: 时间(秒)
- phi: 相位
我们希望电流值(V)在频率变化前后相同。为此,我们需要更改前后的频率 (f) 和相位 (phi)。
首先我们可以设置第一个等式等于第二个:
V0 + A * sin(2 * pi * f1 * t + phi1) = V0 + A * sin(2 * pi * f2 * t + phi2)
做一些取消:
2 * pi * f1 * t + phi1 = 2 * pi * f2 * t + phi2
求解最终公式的新阶段:
phi2 = 2 * pi * t * (f1 - f2) + phi1
更多数学版本:
已编辑:
签出修改 fiddle:https://jsfiddle.net/potterjm/qy1s8395/1/