[Git][NTPsec/ntpsec][master] 3 commits: Add commas to glassary numbers.

Gary E. Miller gitlab at mg.gitlab.com
Sat Oct 1 02:59:40 UTC 2016


Gary E. Miller pushed to branch master at NTPsec / ntpsec


Commits:
ba5b9eb4 by Gary E. Miller at 2016-09-30T17:11:49-07:00
Add commas to glassary numbers.

- - - - -
e5ce3193 by Gary E. Miller at 2016-09-30T19:19:20-07:00
Special case percentage==100

- - - - -
601a5bf3 by Gary E. Miller at 2016-09-30T19:58:15-07:00
Move the spread out spread out stats work into class VizStats

Now just one place to tweak autoranging, html presentations.

- - - - -


2 changed files:

- ntpstats/ntpviz
- pylib/statfiles.py


Changes:

=====================================
ntpstats/ntpviz
=====================================
--- a/ntpstats/ntpviz
+++ b/ntpstats/ntpviz
@@ -62,6 +62,98 @@ def pstdev(data, mu=None):
     return pvar**0.5
 
 # end standard deviation functions
+
+# class for calced values
+class VizStats(NTPStats):
+    percs       = {}          # dictionary of percentages
+    unit        = 's'         # display units: s, ppm, etc.
+    multiplier  = 1
+    ninetynine  = 0     # 99%
+    ninetyfive  = 0     # 90%
+    fifty       = 0     # 50%
+    five        = 0     # 5%
+    one         = 0     # 1%
+
+    nf_m_f      = 0     # 95% - 5%
+    nn_m_o      = 0     # 99% - 1%
+
+    mu          = 0     # arithmetic mean
+    pstd        = 0     # population standard distribution, one sigma
+
+    stats_html  = ''
+    
+    def __init__( self, values, freq=0 ):
+
+        values.sort()
+        self.percs = self.percentiles( (100, 99, 95, 50, 5, 1, 0), values)
+
+        # find the target for autoranging
+        # keep 99% and 5% under 999 in selected units
+        # but do not let 100% and 1% go over 5000 in selected units
+        target = max(self.percs[99], -self.percs[1], self.percs[100]/5,
+                     -self.percs[0]/5)
+        if 1 <= target:
+            # go to seconds
+            self.multiplier = 1
+            if freq:
+                self.unit = "ppo"
+            else:
+                self.unit = "s"
+
+        elif 1e-3 <= target:
+            # go to millisec
+            self.multiplier = 1e3
+            if freq:
+                self.unit = "ppt"
+            else:
+                self.unit = "ms"
+
+        elif 1e-6 <= target:
+            # go to microsec, or ppm
+            self.multiplier = 1e6
+            if freq:
+                self.unit = "ppm"
+            else:
+                self.unit = "µs"
+
+        else:
+            # go to nanosec, or ppb
+            self.multiplier = 1e9
+            if freq:
+                self.unit = "ppb"
+            else:
+                self.unit = "ns"
+
+        self.percs.update({k: v * self.multiplier
+                     for k, v in list(self.percs.items())})
+
+        self.ninetynine  = self.percs[99]
+        self.ninetyfive  = self.percs[95]
+        self.fifty       = self.percs[50]
+        self.five        = self.percs[5]
+        self.one         = self.percs[1]
+
+        self.nf_m_f     = self.ninetyfive - self.five
+        self.nn_m_o     = self.ninetynine - self.one
+
+        self.mu = mean( values )
+        self.pstd = pstdev( values, mu=self.mu ) * self.multiplier
+        self.mu *= self.multiplier
+        self.stats_html =  """\
+<p>Percentiles: 99%% = %(ninetynine)s %(unit)s,  
+ 95%% = %(ninetyfive).3f  %(unit)s,  
+ 50%% = %(fifty).3f  %(unit)s,  
+ 5%% = %(five).3f  %(unit)s,  
+ 1%% = %(one).3f  %(unit)s<br>
+Ranges: 99%% - 1%% = %(nn_m_o).3f %(unit)s,  
+ 95%% - 5%% = %(nf_m_f).3f %(unit)s<br>
+Deviation: Mean = %(mu).3f %(unit)s,   
+1σ = %(pstd).3f %(unit)s</p>
+""" % self.__dict__
+
+
+# end calc things now
+
 # RMS frequency jitter - Deviation from a root-mean-square linear approximation?
 # Investigate.
 
@@ -125,29 +217,18 @@ set rmargin 12
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
         sitename = self.sitename
-        unit = "μs"
-        multiplier = 1e6
-        values = [float(line.split()[1]) for line in self.loopstats]
-        values.sort()
-
-        percs = self.percentiles( (99, 1), values)
 
-        if 1e-6 > percs[99] and -1e-6 < percs[1]:
-            # go to nanosec
-            unit = "ns"
-            multiplier = 1e9
+        # compute clock offset
+        values = [float(line.split()[1]) for line in self.loopstats]
+        stats = VizStats( values )
+        unit = stats.unit
+        multiplier = stats.multiplier
 
-        unit_f = "ppm"
-        multiplier_f = 1
+        # compute frequency offset
         values_f = [float(line.split()[2]) for line in self.loopstats]
-        values_f.sort()
-
-        percs_f = self.percentiles( (99, 1), values_f)
-
-        if 1 > percs_f[99] and -1 < percs_f[1]:
-            # go to nanosec
-            unit_f = "ppb"
-            multiplier_f = 1e3
+        stats = VizStats( values_f, freq=1 )
+        unit_f = stats.unit
+        multiplier_f = stats.multiplier
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: Local Clock Time/Frequency Offsets"
@@ -173,7 +254,7 @@ file.</p>
 
 """
 
-        ret = {'html' : exp, 'percs' : percs }
+        ret = {'html' : exp, 'percs' : stats.percs }
         ret['title'] = "Local Clock Time/Frequency Offsets"
         ret['plot'] = plot_template + self.dump("loopstats") + "e\n" \
              + self.dump("loopstats")
@@ -277,34 +358,25 @@ a local gpsd daemon, and logging the data using gps-log.py.</p>
             return ''
         sitename = self.sitename
         # grab and sort the values, no need for the timestamp, etc.
-        values = [float(line.split()[2]) for line in self.loopstats]
-        values.sort()
-
-        multiplier = 1
-        unit = "ppm"
-        rnd = 3
-
-        percs = self.percentiles( (99, 95, 50, 5, 1), values)
 
-        if 1 > percs[99] and -1 < percs[1]:
-            # go to ppb
-            multiplier = 1e3
-            unit = "ppb"
-            rnd = 0
+        # compute freqency offset
+        values = [float(line.split()[2]) for line in self.loopstats]
+        stats = VizStats( values, freq=1 )
+        unit = stats.unit
+        multiplier = stats.multiplier
+        percs = stats.percs
 
-        percs.update({k: round( v * multiplier, rnd) for k, v in list(percs.items())})
-        ninetynine  = percs[99]
-        ninetyfive  = percs[95]
-        fifty       = percs[50]
-        five        = percs[5]
-        one         = percs[1]
+        ninetynine  = stats.ninetynine
+        ninetyfive  = stats.ninetyfive
+        fifty       = stats.fifty
+        five        = stats.five
+        one         = stats.one
 
-        nf_m_f     = percs[95] - percs[5]
-        nn_m_o     = percs[99] - percs[1]
+        nf_m_f      = stats.nf_m_f
+        nn_m_o      = stats.nn_m_o
 
-        mu = mean( values )
-        values_pstd = pstdev( values, mu=mu ) * multiplier
-        mu *= multiplier
+        mu          = stats.mu
+        pstd        = stats.pstd
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: Local Clock Frequency Offset"
@@ -321,15 +393,6 @@ plot \
 """ % locals()
 
         exp = """\
-<p>Percentiles: 99%% = %(ninetynine)s %(unit)s,  
- 95%% = %(ninetyfive).3f  %(unit)s,  
- 50%% = %(fifty).3f  %(unit)s,  
- 5%% = %(five).3f  %(unit)s,  
- 1%% = %(one).3f  %(unit)s<br>
-Ranges: 99%% - 1%% = %(nn_m_o).3f %(unit)s,  
- 95%% - 5%% = %(nf_m_f).3f %(unit)s<br>
-Deviation: Mean = %(mu).3f %(unit)s,  
-1σ = %(values_pstd).3f %(unit)s</p>
 <p>This shows the frequency offset of the local clock (aka drift).  The
 graph includes percentile data to show how much the frequency changes
 over a longer period of time.  The majority of this change should come
@@ -341,7 +404,7 @@ line at 0ppm.  Expected values of 99%%-1%% percentiles: 0.4ppm</p>
 
 <p>The Frequency Offset comes from field 3 of the loopstats log file.</p>
 """ % locals()
-        ret = {'html' : exp, 'percs' : percs }
+        ret = {'html' : stats.stats_html + exp, 'percs' : stats.percs }
         ret['title'] = "Local Clock Frequency Offset"
         ret['plot'] = plot_template + self.dump("loopstats")
         return ret
@@ -352,10 +415,27 @@ line at 0ppm.  Expected values of 99%%-1%% percentiles: 0.4ppm</p>
             sys.stderr.write("ntpviz: WARNING: no loopstats to graph\n")
             return ''
 
-        multiplier = 1e6
-        rnd = 3
+        sitename   = self.sitename
+        # grab and process the values
+        values = [float(line.split()[fld - 1]) for line in self.loopstats]
+        stats = VizStats( values, freq=freq )
+        unit = stats.unit
+        multiplier = stats.multiplier
+        percs = stats.percs
+
+        ninetynine  = stats.ninetynine
+        ninetyfive  = stats.ninetyfive
+        fifty       = stats.fifty
+        five        = stats.five
+        one         = stats.one
+
+        nf_m_f      = stats.nf_m_f
+        nn_m_o      = stats.nn_m_o
+
+        mu          = stats.mu
+        pstd        = stats.pstd
+
         if freq:
-            unit = "ppm"
             title = "Local Stability"
             exp = """\
 <p>This shows the RMS Frequency Jitter (aka wander) of the local
@@ -368,7 +448,6 @@ freqency.</p>
 <p> RMS Frequency Jitter is field 6 in the loopstats log file.</p>
 """
         else:
-            unit = "μs"
             title = "Local Time RMS Jitter"
             exp = """\
 <p>This shows the RMS Jitter of the local clock offset.  In other words,
@@ -379,44 +458,6 @@ how fast the local clock offset is changing.</p>
 <p>RMS jitter is field 5 in the loopstats log file.</p>
 """
 
-        sitename   = self.sitename
-        # grab and sort the values, no need for the timestamp, etc.
-        values = [float(line.split()[fld - 1]) for line in self.loopstats]
-        values.sort()
-
-        percs = self.percentiles( (99, 95, 50, 5, 1), values)
-
-        if 1e-3 <= percs[99] or -1e-3 >= percs[1]:
-            # go to millisec
-            multiplier = 1e3
-            if freq:
-                unit = "ppt"
-            else:
-                unit = "ms"
-
-        elif 1e-6 > percs[99] and -1e-6 < percs[1]:
-            # go to nanosec, or ppb
-            multiplier = 1e9
-            rnd = 0
-            if freq:
-                unit = "ppb"
-            else:
-                unit = "ns"
-
-        percs.update({k: round( v * multiplier, rnd) \
-                     for k, v in list(percs.items())})
-        ninetynine  = percs[99]
-        ninetyfive  = percs[95]
-        fifty       = percs[50]
-        five        = percs[5]
-        one         = percs[1]
-
-        nf_m_f     = ninetyfive - five
-        nn_m_o     = ninetynine - one
-
-        mu = mean( values )
-        values_pstd = pstdev( values, mu=mu ) * multiplier
-        mu *= multiplier
 
         plot_template = NTPViz.Common + """\
 set title "%(sitename)s: %(title)s"
@@ -432,19 +473,8 @@ plot \
  %(one)s title "1st percentile"
 """ % locals()
 
-        exp = ( """\
-<p>Percentiles: 99%% = %(ninetynine)s %(unit)s,  
- 95%% = %(ninetyfive).3f  %(unit)s,  
- 50%% = %(fifty).3f  %(unit)s,  
- 5%% = %(five).3f  %(unit)s,  
- 1%% = %(one).3f  %(unit)s<br>
-Ranges: 99%% - 1%% = %(nn_m_o).3f %(unit)s,  
- 95%% - 5%% = %(nf_m_f).3f %(unit)s<br>
-Deviation: Mean = %(mu).3f %(unit)s,   
-1σ = %(values_pstd).3f %(unit)s</p>
-""" % locals() ) +  exp
-
-        ret = {'html' : exp, 'percs' : percs, 'title' : title }
+        ret = {'html' : stats.stats_html + exp, 'percs' : percs, 
+               'title' : title }
         ret['plot'] = plot_template + self.dump("loopstats")
         return ret
 
@@ -497,49 +527,28 @@ Deviation: Mean = %(mu).3f %(unit)s,   
             title += ": "+ peerlist[0]
             # grab and sort the values, no need for the timestamp, etc.
             values = [float(line.split()[fld - 1]) for line in peerdict[ip]]
-            values.sort()
-
-            percs = self.percentiles( (99, 95, 50, 5, 1), values)
-
-            if 1e-3 <= percs[99] or -1e-3 >= percs[1]:
-                # go to millisec
-                unit = "ms"
-                multiplier = 1e3
-            elif 1e-6 > percs[99] and -1e-6 < percs[1]:
-                # go to nanosec
-                unit = "ns"
-                multiplier = 1e9
-
-            rnd = 3
-            percs.update({k: round(v*multiplier, rnd) for k, v in list(percs.items())})
-            ninetynine  = percs[99]
-            ninetyfive  = percs[95]
-            fifty       = percs[50]
-            five        = percs[5]
-            one         = percs[1]
-
-            # show percentages
-            nf_m_f     = ninetyfive - five
-            nn_m_o     = ninetynine - one
-
-            mu = mean( values )
-            values_pstd = pstdev( values, mu=mu ) * multiplier
-            mu *= multiplier
+
+            stats = VizStats( values )
+            unit        = stats.unit
+            multiplier  = stats.multiplier
+            percs       = stats.percs
+
+            ninetynine  = stats.ninetynine
+            ninetyfive  = stats.ninetyfive
+            fifty       = stats.fifty
+            five        = stats.five
+            one         = stats.one
+
+            nf_m_f      = stats.nf_m_f
+            nn_m_o      = stats.nn_m_o
+
+            mu          = stats.mu
+            pstd        = stats.pstd
 
             percentages = " %(fifty)s title '50th percentile', " \
                            % locals()
 
-            exp = """\
-<p>Percentiles: 99%% = %(ninetynine).3f %(unit)s,  
- 95%% = %(ninetyfive).3f  %(unit)s,  
- 50%% = %(fifty).3f  %(unit)s,  
- 5%% = %(five).3f  %(unit)s,  
- 1%% = %(one).3f  %(unit)s<br>
-Ranges: 99%% - 1%% = %(nn_m_o).3f %(unit)s,  
- 95%% - 5%% = %(nf_m_f).3f %(unit)s<br>
-Deviation: Mean = %(mu).3f %(unit)s,   
-1σ = %(values_pstd).3f %(unit)s</p>
-""" % locals()
+            exp = stats.stats_html
 
             if "offset" == type:
                 # doing offset, not jitter
@@ -669,46 +678,41 @@ plot \
 
         # grab and sort the values, no need for the timestamp, etc.
         values = [float(line.split()[1]) for line in self.loopstats]
-        values.sort()
+        stats = VizStats( values )
+        unit        = stats.unit
+        multiplier  = stats.multiplier
+        percs       = stats.percs
+
+        ninetynine  = stats.ninetynine
+        ninetyfive  = stats.ninetyfive
+        fifty       = stats.fifty
+        five        = stats.five
+        one         = stats.one
+
+        nf_m_f      = stats.nf_m_f
+        nn_m_o      = stats.nn_m_o
+
+        mu          = stats.mu
+        pstd        = stats.pstd
 
         percs = self.percentiles( (99, 95, 50, 5, 1), values)
 
-        unit = "μs"
-        multiplier = 1e6
-        rnd = 2
         rnd1 = 7        # round to 100 ns boxes
         boxwidth = 1e-7
         if 1e-6 > percs[99] and -1e-6 < percs[1]:
             # go to nanosec
-            unit = "ns"
-            multiplier = 1e9
-            rnd = 0
             rnd1 = 9        # round to 1 ns boxes
             boxwidth = 1e-9
 
-        percs.update({k: round(v*multiplier, rnd) for k, v in list(percs.items())})
-        ninetynine  = percs[99]
-        ninetyfive  = percs[95]
-        fifty       = percs[50]
-        five        = percs[5]
-        one         = percs[1]
-
-        nf_m_f     = ninetyfive - five
-        nn_m_o     = ninetynine - one
-
         cnt = collections.Counter()
         for value in values:
             # put into buckets
             # for a +/- 50 microSec range that is 1,000 buckets to plot
             cnt[ round( float(value), rnd1)] += 1
 
-        mu = mean( values )
-        values_pstd = pstdev( values, mu=mu ) * multiplier
-        mu *= multiplier
-
         # plus/minus of one sigma range
-        m1sigma = mu - values_pstd
-        p1sigma = mu + values_pstd
+        m1sigma = mu - pstd
+        p1sigma = mu + pstd
 
         plot_template = '''\
 set terminal png size 900,600
@@ -747,18 +751,9 @@ plot \
         histogram_data = ["%s %s\n" % (val, cnt[val]) for val in vals]
 
         exp = """\
-<p>Percentiles: 99%% = %(ninetynine).3f %(unit)s,  
- 95%% = %(ninetyfive).3f  %(unit)s,  
- 50%% = %(fifty).3f  %(unit)s,  
- 5%% = %(five).3f  %(unit)s,  
- 1%% = %(one).3f  %(unit)s<br>
-Ranges: 99%% - 1%% = %(nn_m_o).3f %(unit)s,  
- 95%% - 5%% = %(nf_m_f).3f %(unit)s<br>
-Deviation: Mean = %(mu).3f %(unit)s,   
-1σ = %(values_pstd).3f %(unit)s</p>
 <p>This shows the clock offsets of the local clock as a histogram.</p>
 """ % locals()
-        ret = {'html' : exp, 'percs' : percs }
+        ret = {'html' : stats.stats_html + exp, 'percs' : percs}
         ret['title'] = "Local Clock Time Offset Histogram"
         ret['plot'] = plot_template + "".join(histogram_data)
         return ret
@@ -1126,15 +1121,16 @@ number of values.</dd>
 
 <dt>ppb, parts per billion:</dt>
 <dd>Ratio between two values. These following are all the same:
-    1 ppb, one in one billion, 1/1000000000, 0.000000001, and 0.0000001%</dd>
+    1 ppb, one in one billion, 1/1,000,000,000, 0.000,000,001, and
+    0.000,000,1%</dd>
 
 <dt>ppm, parts per million:</dt>
 <dd>Ratio between two values. These following are all the same:
-    1 ppm, one in one million, 1/1000000, 0.000001, and 0.0001%</dd>
+    1 ppm, one in one million, 1/1,000,000, 0.000,001, and 0.000,1%</dd>
 
 <dt>ppt, parts per thousand:</dt>
 <dd>Ratio between two values. These following are all the same:
-    1 ppt, one in one thousand, 1/1000, 0.001, and 0.1%</dd>
+    1 ppt, one in one thousand, 1/1,000, 0.001, and 0.1%</dd>
 
 <dt>refclock:</dt>
 <dd>Reference clock, a local GPS module or other local source of time.</dd>
@@ -1158,7 +1154,7 @@ deviation.  Three sigma is three times sigma.  Smaller is better.</dd>
 
 <dt>µs, us, microsecond:</dt>
 <dd>One millionth of a second, also one thousandth of a millisecond,
-0.000001s.</dd>
+0.000,001s.</dd>
 </dl>
 
 <br>


=====================================
pylib/statfiles.py
=====================================
--- a/pylib/statfiles.py
+++ b/pylib/statfiles.py
@@ -144,7 +144,10 @@ class NTPStats:
         ret = {}
         length = len(values)
         for perc in percents:
-            ret[perc] = values[int(length * (perc/100))]
+            if perc == 100:
+                ret[100] = values[length - 1]
+            else:
+                ret[perc] = values[int(length * (perc/100))]
         return ret
 
     def peersplit(self):



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/d03c62037d87c6cb3e2ac17f1a8f9f5b66a3d7b2...601a5bf33f71b0a942b869a3c8dab05faf364127
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ntpsec.org/pipermail/vc/attachments/20161001/07694efc/attachment.html>


More information about the vc mailing list