当然,你可以通过将剩余文件大小除以当前下载速度来计算下载所需时间,但如果你的下载速度波动较大(而且它会),这样计算出来的结果并不是很准确。那么有没有更好的算法来产生更平滑的倒计时呢?
当然,你可以通过将剩余文件大小除以当前下载速度来计算下载所需时间,但如果你的下载速度波动较大(而且它会),这样计算出来的结果并不是很准确。那么有没有更好的算法来产生更平滑的倒计时呢?
一种指数移动平均非常适合这种情况。它提供了一种将平均值平滑化的方法,因此每次添加新样本时,较旧的样本对整体平均值的重要性逐渐降低。 它们仍然被考虑在内,但其重要性呈指数级下降--因此得名。由于它是“移动”的平均值,您只需要保留一个数字。
在衡量下载速度的背景下,公式如下:
averageSpeed = SMOOTHING_FACTOR * lastSpeed + (1-SMOOTHING_FACTOR) * averageSpeed;
SMOOTHING_FACTOR
是一个介于 0 和 1 之间的数字。这个数字越高,旧样本被丢弃得越快。正如你在公式中看到的那样,当 SMOOTHING_FACTOR
为 1 时,你只是使用了你最后一次观察的值。当 SMOOTHING_FACTOR
为 0 时,averageSpeed
永远不会改变。所以,你需要介于两者之间的某些值,通常选择一个较低的值来获得良好的平滑效果。我发现 0.005 对于平均下载速度提供了相当不错的平滑效果。
lastSpeed
是最后一次测量的下载速度。你可以通过每秒运行一个计时器来获取这个值,以计算自上次运行以来下载了多少字节。
averageSpeed
显然是你要用来计算估计剩余时间的数值。将其初始化为你获取到的第一个 lastSpeed
值。
speed=speedNow*0.5+speedLastHalfMinute*0.3+speedLastMinute*0.2
我认为最好的做法是将剩余文件大小除以平均下载速度(已下载部分除以下载时间)。这个值一开始会有些波动,但随着下载时间的增加,会越来越稳定。
我发现Ben Dolman的回答非常有帮助,但对于像我这样不太擅长数学的人来说,仍然需要花费大约一个小时才能完全将其实现到我的代码中。以下是在Python中以更简单的方式表达相同内容的方法,如果有任何不准确之处,请让我知道,但在我的测试中它非常有效:
def exponential_moving_average(data, samples=0, smoothing=0.02):
'''
data: an array of all values.
samples: how many previous data samples are avraged. Set to 0 to average all data points.
smoothing: a value between 0-1, 1 being a linear average (no falloff).
'''
if len(data) == 1:
return data[0]
if samples == 0 or samples > len(data):
samples = len(data)
average = sum(data[-samples:]) / samples
last_speed = data[-1]
return (smoothing * last_speed) + ((1 - smoothing) * average)
input_data = [4.5, 8.21, 8.7, 5.8, 3.8, 2.7, 2.5, 7.1, 9.3, 2.1, 3.1, 9.7, 5.1, 6.1, 9.1, 5.0, 1.6, 6.7, 5.5, 3.2] # this would be a constant stream of download speeds as you go, pre-defined here for illustration
data = []
ema_data = []
for sample in input_data:
data.append(sample)
average_value = exponential_moving_average(data)
ema_data.append(average_value)
# print it out for visualization
for i in range(len(data)):
print("REAL: ", data[i])
print("EMA: ", ema_data[i])
print("--")
除了Ben Dolman的答案外,您也可以在算法中计算波动。这将使其更加平滑,但也会预测平均速度。
类似这样:
prediction = 50;
depencySpeed = 200;
stableFactor = .5;
smoothFactor = median(0, abs(lastSpeed - averageSpeed), depencySpeed);
smoothFactor /= (depencySpeed - prediction * (smoothFactor / depencySpeed));
smoothFactor = smoothFactor * (1 - stableFactor) + stableFactor;
averageSpeed = smoothFactor * lastSpeed + (1 - smoothFactor) * averageSpeed;
无论是否波动,只要设置正确,使用预测值和依赖速度,它将与其他设置一样稳定。根据你的互联网速度稍微进行调整。这些设置非常适合平均速度为600 kB/s的情况,尽管会在0到1MB之间波动。