user1008784
user1008784

Reputation:

WebClient DownloadDataAsync current download speed

I'm trying to get the current download speed of a WebClient downloading a file, however when I use a formula that I'm pretty sure should work out:

Stopwatch.Stop();
double msElapsed = Stopwatch.Elapsed.TotalMilliseconds;
int bytesDownloaded = (int)e.BytesReceived - lastBytesDownloaded;
double downloadSpeed = (double)bytesDownloaded / (msElapsed / 1000);
lastBytesDownloaded = (int)e.BytesReceived;
Stopwatch.Restart();

Where Stopwatch is a stopwatch that I've started just as I started the file download, lastBytesDownloaded is a class variable, and this is all inside the downloadProgressChanged event, however the download speed varies wildly off course from what it actually is.

For example if I was downloading a file at 500kb/s, it would rapidly jump from (for example) 10kb/s to 50mb/s completely randomly.

I can get an accurate average download time by making a couple edits to that:

double sElapsed = Stopwatch.Elapsed.TotalSeconds;
int bytesDownloaded = (int)e.BytesReceived;
double downloadSpeed = bytesDownloaded / sElapsed;

But that isn't what I want. How can I get a more stable reading for current download speed?

Upvotes: 2

Views: 2207

Answers (1)

Jon
Jon

Reputation: 437326

You just need to smooth the data over a longer period of time. For example, don't report current download speed only on the basis of the last measurement; use a (perhaps weighted) moving average instead.

Dead simple example:

var measurements = 0, maxDataPoints = 5;
var dataPoints = new double[maxDataPoints];

And then:

Stopwatch.Stop();
double msElapsed = Stopwatch.Elapsed.TotalMilliseconds;
int bytesDownloaded = (int)e.BytesReceived - lastBytesDownloaded;
lastBytesDownloaded = (int)e.BytesReceived;
double dataPoint = (double)bytesDownloaded / (msElapsed / 1000);
dataPoints[measurements++ % maxDataPoints] = dataPoint;

double downloadSpeed = dataPoints.Average();
Stopwatch.Restart();

Upvotes: 2

Related Questions