-
Notifications
You must be signed in to change notification settings - Fork 0
Changelog
All notable changes to this project are documented here. The format follows Keep a Changelog and the project uses Semantic Versioning:
- MAJOR: incompatible changes to the Python API, CLI options or file formats written;
- MINOR: new statistics, formats, commands or UI features (backwards compatible);
- PATCH: bug fixes and documentation.
Releases are made from vX.Y.Z tags (see CONTRIBUTING.md). The Release workflow checks the
tag against the package version, tests, publishes a GitHub Release with the notes below and
uploads to PyPI.
Research bench v2, part 1 (#29). The new modules are provisional (not yet in ntpstats.api) until
2.17 adds the simulator exchange formats.
-
Delay traces (
ntpstats.trace,ntpstats trace): per-direction one-way delays extracted from any two-way exchanges.- Inputs: NTP and PTP captures, chrony
measurements.log, ntpdpeerstats/rawstats, and simulator output. - The clock offset between the two ends is removed (
--detrend floor|linear|none). - The asymmetry is an explicit assumption (
--asymmetry), since two-way timestamps cannot measure it. -
ntpstats tracereports floors, PDV percentiles, loss and the correlation of the two directions;--csvexports the trace.
- Inputs: NTP and PTP captures, chrony
-
Trace replay in the bench:
ntpstats bench trace:FILE, or a[trace]table in a scenario file.- Modes:
replayplays the trace in order;bootstrapdraws random blocks, keeping the short-term correlation and both directions together. -
scalemultiplies the queueing. - Checked by a round trip: delays extracted from a simulated network and replayed give the same estimator scores as the model they came from.
- Modes:
-
PTP servos and boundary-clock chains (
ntpstats.ptpsim,ntpstats chain): a grandmaster and N boundary clocks, simulated with ground truth.- Each node has its own oscillator, the E2E delay mechanism with a moving-median filter, and linuxptp's PI servo (with its default gains) or an adaptive linear-regression servo.
- Links have asymmetry, timestamp noise, and modelled or replayed PDV.
- Time-error metrics are given per node and per hop: max|TE|, |cTE|, dTE_L MTIE, dTE_H.
- Each hop is checked against the commonly quoted G.8273.2 T-BC class limits (A/B/C) or your own limits, and the end of the chain against a budget (default 1.1 µs); exit code 3 on failure.
-
--kp/--kitune the servo. The warm-up follows the servo's lock time, and the command warns when a run is too short to lock.
- New notebook: a PTP chain against a time-error budget. With linuxptp's default gains, dynamic time error grows much faster than the number of hops (gain peaking): about 50 ns at 10 hops, about 600 ns at 20. A narrower loop keeps 20 hops near 25 ns. The bench notebook now also replays a real log.
- Noise identification no longer divides by zero on perfectly alternating or noise-free data (lag-1 autocorrelation of −1, the white-PM limit).
- Commands piped into
headand similar tools stop quietly instead of printing aBrokenPipeErrortraceback.
-
Stable API (#32):
from ntpstats import api as ntgives the public surface in one namespace (loading, stability, analysis, metrology, time error and assurance, estimators, simulator, bench, reports, plugin types).- Covered by a deprecation policy: one full minor release of
NtpstatsDeprecationWarningbefore a stable name or parameter changes. The warning is aFutureWarning, so it is shown in scripts and notebooks. - Helpers for contributors in
ntpstats.deprecation:deprecated,renamed_parameter,moved. - The surface is frozen in
tests/data/api_surface.json; CI fails on incompatible changes. - Documented on the new Stable API page; the policy is in CONTRIBUTING.
- Covered by a deprecation policy: one full minor release of
-
Large files (#32, continues #13):
load_largeanditer_chunksread line-oriented logs in blocks, gzip included, and give the same series asload.- In a 300 000-line test, peak memory was about 2.4 times lower and reading twice as fast.
-
loadswitches to block reading by itself for text logs above 256 MB. - Supported formats: ntpd/NTPsec stats, chrony logs, linuxptp, CSV and the 2012 log.
-
Notebooks and reproduction gallery (#32, #38): four notebooks, executed in CI on every change:
- a chrony log to stability with intervals and a noise model;
- benchmarking your own estimator;
- compliance evidence (PTP time error, a UTC bound, a mask, an HTML report);
- a reproduction of the NIST SP 1065 test suites.
A docs page explains how to contribute a gallery entry.
With these, #32 is complete. Its last step, a 3.0 changelog that lists every change to the stable API, is part of the 3.0 release checklist (CONTRIBUTING). The research bench v2 (#29) is planned for 2.16 and 2.17.
-
In-browser edition (#31): the web UI runs entirely in the browser on the docs site, with
Pyodide (WebAssembly). Files never leave the machine.
docs/build_app.pybuilds it from the package wheel; a CI job checks with Playwright and Chromium that the page gives the same numbers as the installed package. Live probes stay in the installed tool. -
Plugins (#37): other packages add parsers, estimators, event detectors, masks and import
profiles through entry points (
ntpstats.parsers,.estimators,.detectors,.masks,.profiles).-
ntpstats pluginslists everything, with where it comes from and load errors. - A plugin that fails to load is reported and never breaks the tool.
- Contract tests for plugin authors:
pytest --pyargs ntpstats.testing.plugin_contract. - Worked example in
examples/plugins/ntpstats-toy-csv, installed and checked in CI. - The built-in research formats are registered through the same API.
-
-
Dataframes and Parquet (part of #32):
TimeSeries.to_pandas()/from_pandas(),StabilityResult.to_dataframe(),DynamicResult.to_xarray(), and Parquet files that keep float64 precision and the metadata (convert --to parquet; Parquet input is auto-detected). Optional extrantpstats[data]; the package ships apy.typedmarker.
- The web server's
/apirouting is a plaindispatch()function, shared by the HTTP server and the browser edition. The UI's format list comes from/api/info, so plugin formats appear.
-
Open interop dataset (#30): the first Live interop run of each month writes one JSON record per probe
(NTP, interleaved, NTS, NTS pool, NTPv5, Roughtime) to
data/interop/YYYY/YYYY-MM-DD.jsonl, committed with[skip ci]. The dataset ships with each release, so it is archived on Zenodo.- Schema:
data/interop/README.md. - New
interopinput format: one series per test and server, with availability. -
ntpstats dataset: summary per server. - A directory given to any command is read as the concatenation of its files.
- Schema:
-
OpenTelemetry export (#36):
monitor/watch --otlp [URL]push the metrics as OTLP/HTTP JSON, standard library only; the standardOTEL_*environment variables are honoured. The payload is checked against the official OpenTelemetry protobuf definitions. - Cross-validation (#28): the exact EDF is compared with the SP 1065 table 5 approximations used by Stable32: within 3 % for white PM/FM, 7 % for flicker/random-walk FM, 16 % for flicker PM.
- Roughtime: the client also offers draft-08 (0x80000008), and falls back to Google-Roughtime (the pre-IETF protocol: unframed, 64-byte nonces, microseconds) when a server does not answer the IETF request. Cloudflare's server did not answer in the 2.11 live interop run; the protocol that answered is reported and recorded in the dataset.
-
Power-law noise model (#25):
ntpstats noiseandntpstats.noisefitfit h₂…h₋₂ and, optionally, a linear drift to OADEV/MDEV/HDEV curves and the spectrum.- The expected estimator values are exact for the discrete Kasdin–Walter model.
- Model selection uses BIC.
- Intervals come from a parametric bootstrap. Monte Carlo coverage is ≥ 90 % per coefficient except at the edge of detection.
- Corner τ values are reported.
--scenariowrites a simulator clock ([clock.h_alpha]), andsimulate --scenarioruns it. - The UI can overlay the fitted model on the Stability chart.
-
Spectra (#25):
ntpstats spectrumandntpstats.spectrumcompute S_x(f) and S_y(f) with Welch or sine multitaper, per gap-free stretch, log-binned with degrees of freedom. L(f) in dBc/Hz for a carrier. New Spectrum tab in the UI. -
N-cornered hat (#27):
ntpstats hatandntpstats.hatestimate each source's stability from pairwise differences: Groslambert covariance, three-cornered hat and N-cornered hat by least squares, with intervals. Negative variances are flagged. Sources are aligned from separate logs. -
Holdover prediction (#26):
ntpstats holdoverandntpstats.holdoverpredict TIE(t) with an envelope and the time to violate limits. The 95 % envelope holds 95 % ± 3 % with a known noise model, and 94–100 % with a fitted one.- The variance is computed exactly for the fitted noise, including the error of the fitted frequency and drift.
- The uncertainty of the noise model is mixed into the envelope.
-
--backtestchecks calibration on the log itself;--min-holdoverexits with code 3 when the limit is not held long enough. - Phase can also be integrated from a frequency column (chrony).
- New Holdover tab in the UI.
-
Research data (#34): new formats
cggtts(V2E, line checksums),rinex-clock(IGS.clk),circular-t(BIPM, UTC − UTC(k)),ripe-atlas(NTP results) andntppool(monitor logs).ntpstats cvcomputes GNSS common-view and all-in-view time transfer, andresearch.group_summarygives per-server or per-probe distributions. Gzipped inputs are read directly. -
HTOT (#33): Hadamard total deviation (
-k htot), bias-corrected per noise type, matching the NIST SP 1065 tables within 0.3 %.compat.allantools.htotdevreturns the raw value. - Docs: Metrology and Research data pages;
synthetic examples of every new format in
examples/data/.
-
Roughtime (#24):
ntpstats roughtimeandntpstats.roughtime(draft-ietf-ntp-roughtime-19). It verifies the delegation and response signatures, MINT/MAXT, and the Merkle proof. It chains nonces over two rounds, runs the causal-ordering check, and writes and verifies malfeasance reports. It gives an authenticated interval for the local clock's error (--check-local), bundles the ecosystem server list and reads the draft's server-list JSON. It is compatible with older-draft servers (nonce leaf, microsecond timestamps). -
NTS pools (#24): NTS-KE NTP Server Deny records (draft-ietf-ntp-nts-keyexchange-pool-01),
nts.pool_sessions()andntpstats query --nts --pool Ngive independent servers from one pool. -
RFC 9769 interleaved mode (#24):
ntpstats query --interleavedandsntp.query_interleaved()use the server's precise transmit timestamp. Captures recognise interleaved exchanges, recompute them with the precise timestamp and add aninterleavedcolumn. - Live interop: NTS pool, Roughtime (chained, with the causal check) and interleaved-mode sections. The NTPv5 client stays on draft-09, the current draft.
- Docs: a Protocols page.
-
UTC traceability audit (#22):
ntpstats audit FILE --limit 100us. It computes a per-sample bound (|offset| + path + upstream + reference), stating the rule applied to each term (log columns or user allowances). Windows (1 h) are judged pass/fail/insufficient; gaps count as unmonitored, never as compliant. Output is text, JSON or a self-contained HTML report with the tool version and SHA-256 hashes of the inputs, and the exit code is 3 on failure. -
Change detection (#23):
ntpstats eventsandntpstats.events. It finds phase steps and spikes (MAD against a rolling slope), frequency changes (binary segmentation, standardised CUSUM), delay-floor (route) changes with an asymmetry hint, and leap smears. Phase and frequency events are marked path changed/unchanged. The UI lists events under the Offset chart. -
GitHub Action (#36):
uses: thiagodefreitas/NetworkTime@v2.10.0runs stability, time error, audit, bounds or events checks, writes a job summary and fails on exit code 3. Arguments go through the environment, never through the shell. CI exercises it on the examples. -
pytest assertions (#36):
ntpstats.testing(assert_max_te,assert_time_error_within,assert_stability_within,assert_audit_passes,assert_bounds_valid,assert_no_events) and atiming_logfixture registered as a pytest plugin. - "Audit, events & CI checks" docs page.
-
format_seconds(0)printed "0 ps"; it now prints "0 s".
-
Live PTP clients (#21):
ntpstats watch ptp4lpolls linuxptp throughpmc(CURRENT_DATA_SET, TIME_STATUS_NP), andntpstats watch ptpcheckpolls facebook/timeptpcheck stats. Both are negated into reference − local, offered in the UI's Live dialog, and served to Prometheus with--metrics-port. -
Windows w32tm (#21):
/stripchart /dataonlytext (with midnight rollover and the date taken from the header) and/rdtscCSV with exact FILETIME timestamps, auto-detected. -
Prometheus import (#21, #36):
ntpstats prom URL QUERYsaves a range query (e.g. ntpd-rsntp_source_offset_seconds, chrony_exporter) as JSON, and any command reads it. -
Clock-error bound validation (#21):
ntpstats bounds BOUNDS REFERENCEclassifies each ClockBound/fbclock/CSV window as inside, violated or indeterminate against a better reference (with its uncertainty), and reports the violation rate, worst excess and tightness. Exit code 3 above--max-violation-rate. Windows are parsed as exact decimals. -
Instrument import profiles (#35):
-f profile:NAME|FILE.tomldescribes column layouts (value/time columns, units, TE or offset sign, ISO/MJD/unix/elapsed time, skipped banner rows, extra columns). Built-ins:te-csv,tic-ns,tic-s,iso-te-ns. -
--negateon every command, for sources that log local − reference. - Examples:
w32tm-stripchart.txt,clockbound.txtwith a reference (synthetic), and a "Sources, instruments & bounds" docs page.
-
PTP from packet captures (#19). IEEE 1588 v2/v2.1 over UDP (IPv4/IPv6, ports 319/320)
and Ethernet (0x88F7, VLAN) is read from pcap/pcapng. It supports one- and two-step clocks,
E2E (Delay_Req/Resp) and P2P (peer delay, one- and two-step), and correction fields. The
TAI→UTC offset is taken from Announce or inferred. There is one series per master/slave flow
(offset against the capture clock, path/link delay, one-way delays, corrections), and
AUTHENTICATION TLVs (NTS4PTP) are flagged.
ntpstats.ptp.summary()counts messages. -
Time-error metrics (#20):
ntpstats timeerrorandntpstats.timeerror. They give max|TE|, cTE (record and per 1000 s window), TEL/max|TEL| (0.1 Hz first-order filter, restarted after gaps, settling excluded), dTE_L (peak-to-peak, MTIE, TDEV) and dTE_H peak-to-peak. User-supplied limits (max_te, 30ns…) and MTIE/TDEV masks for dTE_L are checked, with exit code 3 on failure. Time-interval counter input is handled with--units ns --input-is-te. - Time-error cards in the web UI (Overview) and
ntpstats report --time-error. -
examples/data/ptp-capture.pcapng(synthetic) and a "PTP captures & time error" docs page.
- Capture timestamps are kept as integer nanoseconds; a float of POSIX seconds only resolves about 240 ns. NTP offsets from captures are now computed exactly as well.
- Personal email addresses removed from public files; the author is referenced by GitHub profile.
- Cross-validation against NIST SP 1065 (#28). The NBS Monograph 140 data (table 30) and the 1000-point test suite (table 31) are regenerated in the tests. ADEV, OADEV, MDEV, TDEV, HDEV, TOTDEV, MTOT and TTOT agree to the 7 printed digits.
- TTOT (time total deviation), and confidence intervals for MTOT/TTOT from the SP 1065 table 8 EDF.
-
Stable32 data files (#33):
read_stable32/write_stable32inntpstats.interop,-f stable32-phase|stable32-freq, andntpstats convert(any supported log to a Stable32 file or CSV). -
allantools-compatible API (#33):
from ntpstats.compat import allantools as atgivesadev,oadev,mdev,tdev,hdev(non-overlapping),ohdev,totdev,mtotdev,ttotdev,theo1,mtieandtiermswith allantools signatures. -
Prometheus/OpenMetrics exporter (#36):
ntpstats monitor|watch --metrics-port. It serves offset, delay, an error bound (|offset| + delay/2 + root delay/2 + root dispersion), NTS status, rolling TDEV and stddev, and sample and error counters (errors by kind, e.g.kod_rate). -
Grafana dashboard, Prometheus alert rules and a docker-compose stack in
contrib/, with a "Monitoring" docs page. Tests check that the dashboard and rules only use exported metrics. - Docs: "Stable32, TimeLab, allantools" migration page and a tools landscape page.
- Community on-ramp (#38): Code of Conduct (Contributor Covenant 2.1), security policy, issue forms (bug, feature, sample-data contribution), a pull request template, and "ways to contribute" in CONTRIBUTING.
- Releases also publish a container image to
ghcr.io/thiagodefreitas/ntpstats.
-
MTOT is bias-corrected by default, dividing by the factor for the noise type identified at
each τ (white PM 0.94 … random-walk FM 0.69), as Stable32 and the SP 1065 tables do. This
makes MTOT an unbiased estimate of MVAR.
--raw-mtot/bias_correction=Falsegive the raw eq. (27) value, which is what earlier versions reported.
-
ntpstats stability --exactandcompute(..., max_work=0)/series_stability(..., max_work=0)to force the full MTOT/Theo definitions.
-
MTOT, Theo1, TheoBR and TheoH are much faster (#18). MTOT and Theo1 are vectorised
across subsequences. TheoBR computes its bias ratio once per τ grid instead of once per τ.
Above a work limit per τ (
stability.MAX_WORK), subsequences are strided (stride ≤ m), and the TheoBR ratio averages 64 evenly spaced terms. What was sampled is reported inmeta["stride"]andmeta["theobr_ratio_terms"], and the CLI prints a note. On 1M samples at octave τ each statistic takes 2–4 s instead of hours; on 4096 samples TheoBR went from 210 s to under 1 s. Below the limit, results match the literal definitions to 1e-12.
2.5.0 - 2026-09-29
- New stability statistics (#15, closes #2): MTOT (modified total deviation), TheoBR (bias-removed Theo1) and TheoH (hybrid ADEV/TheoBR), in the CLI, API and UI.
-
Documentation site (MkDocs Material,
mkdocs build --strictin CI) with getting started, CLI, formats, statistics, network and estimators, validation, and an API reference generated from docstrings (mkdocstrings). It is deployed to GitHub Pages frommaster. -
GitHub wiki generated from
docs/,CHANGELOG.mdandROADMAP.md(docs/sync_wiki.py, Wiki workflow). - Type checking: mypy in CI, and the package is now mypy-clean.
- Coverage XML report in CI.
-
Releases are tag-driven (
vX.Y.Z), or created from Run workflow with a tag input. The tag must match__version__and have a CHANGELOG section. Wheels and sdists are checked withtwineand published to PyPI through trusted publishing. -
docsextra:mkdocs>=1.5,<2,mkdocs-material,mkdocstrings[python].
- Type errors found by mypy: optional defaults, NTS session key handling, and Optional values in report formatting.
2.4.0 - 2026-09-29
- Web UI: export file names are sanitised and RFC 6266-encoded, which prevents response-header injection through crafted upload names; non-ASCII names no longer truncate responses.
- Web UI: a negative
Content-Lengthis rejected instead of blocking a worker thread. - Web UI:
/api/masktreats the body as mask text only and can no longer read files on the server. - NTS: a Kiss-o'-Death (including NTSN) is honoured only when it echoes the request's Unique Identifier (RFC 8915 §5.7), so a spoofed packet cannot flush the keys.
- NTS: TLS failures during NTS-KE raise
NTSError, which the CLI and monitor handle, instead of surfacing raw pyOpenSSL exceptions. - Masks apply to one statistic, named in the header (
tau,tdev,tau,mtie, …) or set with--mask-kind(default TDEV). They are no longer compared with estimators of other units. - CSV export keeps full sub-second time resolution. It previously used
%.12g, which kept only 2 decimals of POSIX time. - CSV import with a header but no time column now requires
tau0instead of using the offset as time. -
ntpstats networkremoves a linear trend before computing offset statistics, as the UI and report do (--detrend). - Kalman noise fitting no longer fails on constant offsets (zero ADEV).
- Floor packet percentage no longer drops the last sample when the span is an exact multiple of the window.
-
ntpstats simulateno longer mutates the shared presets. -
--tau0is honoured as the stability grid for multi-column files. -
ntpstats report --ci 0no longer crashes. - Live monitor: a late sample from a stopped monitor can no longer land in a newer live dataset.
-
ui --host 0.0.0.0accepts remote Host headers (it is an explicit opt-in). IPv6 bind addresses work.
- Stability confidence intervals: the EDF uses FFT convolution, so 1M-sample OADEV/MDEV/HDEV/TDEV with CIs takes about 1.2 s (previously 28–121 s).
- Parsers use numpy's C tokenizer, with a tolerant per-line fallback: ~1 s per million loopstats lines, ~2.4 s peerstats and ~3 s chrony (previously ~9–10 s). Closes #13.
-
ntpstats compare ESTIMATE REFERENCE: error statistics plus TDEV/MTIE of one source against a reference (e.g. NTP client vs PPS/GNSS). - CI: ruff lint and coverage reporting;
Dockerfilefor the UI/CLI/monitor. - Tests for every fix above (166 tests).
2.3.0 - 2026-09-29
-
Research bench: pluggable estimator API (
ntpstats.estimators, entry-point groupntpstats.estimators) andntpstats bench. It runs scenarios × seeds × estimators against ground truth and reports RMS, bias, p95, max, MTIE(1 h) of the error and runtime, with a 30 min warm-up excluded by default. Output is a table, CSV, JSON or a self-contained HTML report (#9). -
Scenario files in TOML/JSON (
scenario_from_dict) and two examples inexamples/scenarios/(#9). - Reference estimators: chrony-style weighted regression with a runs-test window, RADclock-style feed-forward, RFC 5905 clock filter + selection (intersection), cluster and combine for multiple servers with causal frequency propagation, and a median combiner (#10).
-
Simulator: flicker FM/PM, temperature-driven frequency (tempco), path events (route
change, congestion, outage), multi-server scenarios with falsetickers and stepping servers
(
simulate_multi), and new presetsroute-changeandfalseticker(#11). -
Self-contained HTML reports:
ntpstats report FILES -o report.htmland a Report button in the UI. Offset, stability with CI bands and a noise table, network wedge, input SHA-256 hashes and parameters are embedded, and the file works offline (#12). -
Live interop workflow: weekly/on-demand queries of public NTPv4 and NTS servers plus the
NTPv5 probe from GitHub runners, with a first snapshot in
docs/INTEROP.md(all five NTS servers tested authenticated successfully). -
examples/04_custom_estimator.py: plugging your own algorithm into the bench.
- GitHub Actions updated to
actions/checkout@v5andactions/setup-python@v6(Node 24).
2.2.0 - 2026-09-29
-
chrony
measurements.logoffsets had the wrong sign in 2.0.0–2.1.0. chrony.conf(5) documents θ as "positive indicates that the local clock is slow of the remote source" (the ntpd convention), but the parser negated it. Example data and the cross-format test repeated the same assumption; they are corrected, and a regression test is now pinned to the documentation line.
-
PTP: linuxptp
ptp4l/phc2sys/ts2phcparser, covering per-sample and summary lines, stdout/syslog/journald, monotonic→UTC mapping, and path delay feeding the network metrics (#5). -
chrony
refclocks.logparser (GNSS/PPS reference clocks). -
Live local daemons:
ntpstats watch chrony|ntpd(chronyc -c tracking,ntpq -c rv), also available as a UI Live source (#6). - pcap/pcapng import with stdlib-only dissection (Ethernet/VLAN, Linux cooked, raw IP, IPv4/IPv6). Requests and responses are matched by origin timestamp or v5 client cookie, and offsets are measured from the capture clock (#7).
-
NTS client (RFC 8915) behind the optional extra
ntpstats[nts]: NTS-KE over TLS 1.3 with ALPN, host-name verification, AES-SIV-CMAC-256 and cookie renewal.query --nts,monitor --nts(#8). -
Experimental NTPv5 client (draft-ietf-ntp-ntpv5-09, wire format cross-checked with
ntpd-rs):
query --ntpv5,--probe-v5upgrade negotiation,monitor --ntpv5, UI protocol selector (#8). - Example logs: linuxptp, chrony refclocks and a pcap capture.
2.1.0 - 2026-09-29
-
Exact EDF for ADEV/OADEV/MDEV/TDEV/HDEV confidence intervals (
ntpstats.edf): computed from the estimator filter convolved with the discrete power-law noise model, verified by Monte Carlo for every noise type (#1). - New statistics: TOTDEV (with NIST EDF), Theo1 (τ up to 0.75 × record) and TIErms (#2).
-
Dynamic stability (sliding-window ADEV/MDEV/…):
ntpstats dynamic,stability.dynamic()and a heat-map in the UI (#3). -
Limit masks from user CSV (
tau,limit, log-log interpolation):ntpstats stability --mask FILE(exit code 3 on failure, upper confidence bound used), per-τ margin in the UI and a PASS/FAIL chip (#4). - UI: estimator chips are populated from the server; mask loading; dynamic view toggle.
- Confidence intervals now use the exact discrete EDF. The Greenhall–Riley continuous-time
approximation over-estimated the EDF by up to ~20 % at small averaging factors for
instantaneously sampled phase data.
stability.edf_approxis kept as a deprecated alias.
2.0.0 - 2026-09-29
First release of the rewrite. The 2012 Google Summer of Code prototype is kept unchanged in
legacy/.
- Parsers for ntpd/NTPsec
loopstats,peerstats,rawstats; chronytracking.log,measurements.log,statistics.log; CSV; 2012estimators.log. Auto-detection and sign normalisation (server − local). - Stability statistics: ADEV, OADEV, MDEV, TDEV, HDEV, MTIE with χ² confidence intervals, lag-1 ACF noise identification and gap-aware resampling.
- Network metrics: delay floor, offset/delay wedge, asymmetry indicator, floor packet percentage, min-delay clock filter.
- Kalman filter (delay-weighted, gated, irregular sampling) and RTS smoother.
- Simulator with ground truth and
ntpstats simulate --benchmark. - SNTP client (random transmit timestamp, origin check, KoD, 2036 era) and
ntpstats monitor. - Local web UI (
ntpstats ui), CLI, optional matplotlib report figures. - Test suite, CI, examples, documentation, MIT license.
- Allan deviation τ₀ was hard-coded to 32 s (≈33× error on loopstats data); irregular sampling
and gaps were ignored. See
docs/STATE_OF_THE_ART.md.
ntpstats
- Home
- Getting started
- CLI reference
- In your browser
- Input formats
- Statistics
- Network & estimators
- Trace replay & PTP chains
- PTP & time error
- Sources & bounds
- Audit, events & CI
- Monitoring
- Protocols
- Metrology
- Research data
- Dataframes & Parquet
- Writing a plugin
- Notebooks & gallery
- Validation
- API reference
- Live interop
- State of the art
- Tools landscape
- Changelog
- Roadmap