Calculate a trustworthy interface rate
Calculate receive megabits per second from two counter snapshots and preserve invalid intervals as unknown.
Counters are cumulative, rates use an interval
Each sample contains DeviceId, Port, AtUtc, RxOctets, LinkSpeedBps, and Epoch. RxOctets is a cumulative receive-byte counter. For a valid interval, subtract the counters before converting the difference into bits per second: 8 * deltaBytes / elapsedSeconds. Divide by 1,000,000 for decimal Mbps, not by PowerShell's binary 1MB multiplier.
Convert counters to [decimal] before subtraction. Large counters can exceed the range where a double represents every integer exactly. The lesson tests a tiny delta between counters above 2^53.
Refuse to invent continuity
Require matching interface identities, positive elapsed time, an unchanged Epoch marker, non-negative counters that do not decrease, and the same positive fixed link speed. A reboot can invalidate the interval even when the new counter is larger. A falling counter does not establish that a particular wrap occurred.
For these fixed-speed physical-interface fixtures, a per-direction rate above the link speed is also Unknown. Do not clamp it to 100 percent or replace unknown data with zero. Exactly the link speed is valid; unchanged counters over a valid interval produce a real zero.
The export contract provides parseable offset timestamps and numeric counter/speed fields. This function evaluates their relationships. It returns the later sample's identity, a numeric Mbps rounded to six decimals for Valid results, or null Mbps and a diagnostic for Unknown results.
Go deeper
Get-Content '/home/user/rate-samples.json' -Raw | ConvertFrom-Json | Select-Object AtUtc,RxOctets,LinkSpeedBps,Epoch
Put it into practice.
Define Get-ReceiveRate -Before -After with the interval-validity rules above. Emit DeviceId, Port, State (Valid or Unknown), Mbps, and Error. Valid intervals use decimal Mbps rounded to six places and an empty Error. Unknown intervals retain null Mbps and a non-empty diagnostic. Never assume a counter wrap or clamp an impossible rate.
See an explained solution
function Get-ReceiveRate {
param($Before,$After)
$reason = ''
$mbps = $null
$seconds = ([DateTimeOffset]::Parse($After.AtUtc) - [DateTimeOffset]::Parse($Before.AtUtc)).TotalSeconds
[decimal]$start = $Before.RxOctets
[decimal]$end = $After.RxOctets
if ($Before.DeviceId -ne $After.DeviceId -or $Before.Port -ne $After.Port) { $reason = 'Different interface identities.' }
elseif ($seconds -le 0) { $reason = 'Elapsed time must be positive.' }
elseif ($Before.Epoch -ne $After.Epoch -or $end -lt $start -or $start -lt 0 -or $end -lt 0) { $reason = 'Counter continuity is unavailable.' }
elseif ($Before.LinkSpeedBps -le 0 -or $After.LinkSpeedBps -le 0 -or $Before.LinkSpeedBps -ne $After.LinkSpeedBps) { $reason = 'A stable positive link speed is required.' }
else {
[decimal]$bps = 8 * ($end - $start) / [decimal]$seconds
if ($bps -gt [decimal]$After.LinkSpeedBps) { $reason = 'Observed rate exceeds the fixed link speed.' }
else { $mbps = [math]::Round($bps / 1000000, 6) }
}
[pscustomobject]@{ DeviceId=$After.DeviceId; Port=$After.Port; State=$(if ($reason) { 'Unknown' } else { 'Valid' }); Mbps=$mbps; Error=$reason }
}
The delta remains exact before division, Mbps uses decimal units, and the continuity checks stop resets or inconsistent samples from producing plausible-looking rates.