Tcl Library Source Code

Changes On Branch trunk
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch main Excluding Merge-Ins

This is equivalent to a diff from 61e6db60d3 to 20d3697afb

2025-06-10
01:34
Fix [e5f3dfc055c]: Tcllib 2.0 installer fails with default Tcl build Leaf check-in: 20d3697afb user: culler tags: trunk, main
00:59
Oops. string match does not accept regular expressions. Closed-Leaf check-in: f3ae895f6d user: culler tags: bug-e5f3dfc055c
2025-02-09
15:47
Fixed a typo in permutations proc. check-in: 61f5d52a95 user: arjenmarkus tags: trunk, main
2024-11-19
19:19
Improve the check on the range for the x and y arguments (there should be some variation) check-in: c4478a0624 user: arjenmarkus tags: trunk, main
2024-11-15
08:12
Correct a typo in the description of the elliptic function dn (K.Koehler) Leaf check-in: 61e6db60d3 user: arjenmarkus tags: trunk
2024-11-01
11:06
Bug [f6adf9f137] : correct to-too in error message. Thanks Massimo ! check-in: dc82d34ffc user: oehhar tags: trunk

Changes to embedded/md/tcllib/files/modules/tar/tar.md.
1
2
3
4
5
6
7
8
9
10
11

[//000000001]: # (tar \- Tar file handling)
[//000000002]: # (Generated from file 'tar\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (tar\(n\) 0\.13 tcllib "Tar file handling")

<hr> [ <a href="../../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../../toc.md">Table Of Contents</a> &#124; <a
href="../../../../index.md">Keyword Index</a> &#124; <a
href="../../../../toc0.md">Categories</a> &#124; <a
href="../../../../toc1.md">Modules</a> &#124; <a
href="../../../../toc2.md">Applications</a> ] <hr>



|







1
2
3
4
5
6
7
8
9
10
11

[//000000001]: # (tar \- Tar file handling)
[//000000002]: # (Generated from file 'tar\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (tar\(n\) 0\.14 tcllib "Tar file handling")

<hr> [ <a href="../../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../../toc.md">Table Of Contents</a> &#124; <a
href="../../../../index.md">Keyword Index</a> &#124; <a
href="../../../../toc0.md">Categories</a> &#124; <a
href="../../../../toc1.md">Modules</a> &#124; <a
href="../../../../toc2.md">Applications</a> ] <hr>
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  - [Keywords](#keywords)

  - [Category](#category)

# <a name='synopsis'></a>SYNOPSIS

package require Tcl 8\.5 9  
package require tar ?0\.13?  

[__::tar::contents__ *tarball* ?__\-chan__? ?__\-gzip__?](#1)  
[__::tar::stat__ *tarball* ?file? ?__\-chan__? ?__\-gzip__?](#2)  
[__::tar::untar__ *tarball* *args*](#3)  
[__::tar::get__ *tarball* *fileName* ?__\-chan__? ?__\-gzip__?](#4)  
[__::tar::create__ *tarball* *files* *args*](#5)  
[__::tar::add__ *tarball* *files* *args*](#6)  







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  - [Keywords](#keywords)

  - [Category](#category)

# <a name='synopsis'></a>SYNOPSIS

package require Tcl 8\.5 9  
package require tar ?0\.14?  

[__::tar::contents__ *tarball* ?__\-chan__? ?__\-gzip__?](#1)  
[__::tar::stat__ *tarball* ?file? ?__\-chan__? ?__\-gzip__?](#2)  
[__::tar::untar__ *tarball* *args*](#3)  
[__::tar::get__ *tarball* *fileName* ?__\-chan__? ?__\-gzip__?](#4)  
[__::tar::create__ *tarball* *files* *args*](#5)  
[__::tar::add__ *tarball* *files* *args*](#6)  
Changes to idoc/man/files/modules/tar/tar.n.
1
2
3
4
5
6
7
8
9
10
11
'\"
'\" Generated from file 'tar\&.man' by tcllib/doctools with format 'nroff'
'\"
.TH "tar" n 0\&.13 tcllib "Tar file handling"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\"	Start paragraph describing an argument to a library procedure.
.\"	type is type of argument (int, etc.), in/out is either "in", "out",
.\"	or "in/out" to describe whether procedure reads or modifies arg,



|







1
2
3
4
5
6
7
8
9
10
11
'\"
'\" Generated from file 'tar\&.man' by tcllib/doctools with format 'nroff'
'\"
.TH "tar" n 0\&.14 tcllib "Tar file handling"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\"	Start paragraph describing an argument to a library procedure.
.\"	type is type of argument (int, etc.), in/out is either "in", "out",
.\"	or "in/out" to describe whether procedure reads or modifies arg,
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
..
.BS
.SH NAME
tar \- Tar file creation, extraction & manipulation
.SH SYNOPSIS
package require \fBTcl 8\&.5 9\fR
.sp
package require \fBtar ?0\&.13?\fR
.sp
\fB::tar::contents\fR \fItarball\fR ?\fB-chan\fR? ?\fB-gzip\fR?
.sp
\fB::tar::stat\fR \fItarball\fR ?file? ?\fB-chan\fR? ?\fB-gzip\fR?
.sp
\fB::tar::untar\fR \fItarball\fR \fIargs\fR
.sp







|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
..
.BS
.SH NAME
tar \- Tar file creation, extraction & manipulation
.SH SYNOPSIS
package require \fBTcl 8\&.5 9\fR
.sp
package require \fBtar ?0\&.14?\fR
.sp
\fB::tar::contents\fR \fItarball\fR ?\fB-chan\fR? ?\fB-gzip\fR?
.sp
\fB::tar::stat\fR \fItarball\fR ?file? ?\fB-chan\fR? ?\fB-gzip\fR?
.sp
\fB::tar::untar\fR \fItarball\fR \fIargs\fR
.sp
Changes to idoc/www/tcllib/files/modules/tar/tar.html.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
&#124; <a href="../../../toc.html">Table Of Contents</a>
&#124; <a href="../../../../index.html">Keyword Index</a>
&#124; <a href="../../../../toc0.html">Categories</a>
&#124; <a href="../../../../toc1.html">Modules</a>
&#124; <a href="../../../../toc2.html">Applications</a>
 ] <hr>
<div class="doctools">
<h1 class="doctools_title">tar(n) 0.13 tcllib &quot;Tar file handling&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>tar - Tar file creation, extraction &amp; manipulation</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">BEWARE</a></li>
<li class="doctools_section"><a href="#section3">COMMANDS</a></li>
<li class="doctools_section"><a href="#section4">Bugs, Ideas, Feedback</a></li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#category">Category</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">Tcl 8.5 9</b></li>
<li>package require <b class="pkgname">tar <span class="opt">?0.13?</span></b></li>
</ul>
<ul class="doctools_syntax">
<li><a href="#1"><b class="cmd">::tar::contents</b> <i class="arg">tarball</i> <span class="opt">?<b class="option">-chan</b>?</span> <span class="opt">?<b class="option">-gzip</b>?</span></a></li>
<li><a href="#2"><b class="cmd">::tar::stat</b> <i class="arg">tarball</i> <span class="opt">?file?</span> <span class="opt">?<b class="option">-chan</b>?</span> <span class="opt">?<b class="option">-gzip</b>?</span></a></li>
<li><a href="#3"><b class="cmd">::tar::untar</b> <i class="arg">tarball</i> <i class="arg">args</i></a></li>
<li><a href="#4"><b class="cmd">::tar::get</b> <i class="arg">tarball</i> <i class="arg">fileName</i> <span class="opt">?<b class="option">-chan</b>?</span> <span class="opt">?<b class="option">-gzip</b>?</span></a></li>
<li><a href="#5"><b class="cmd">::tar::create</b> <i class="arg">tarball</i> <i class="arg">files</i> <i class="arg">args</i></a></li>







|



















|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
&#124; <a href="../../../toc.html">Table Of Contents</a>
&#124; <a href="../../../../index.html">Keyword Index</a>
&#124; <a href="../../../../toc0.html">Categories</a>
&#124; <a href="../../../../toc1.html">Modules</a>
&#124; <a href="../../../../toc2.html">Applications</a>
 ] <hr>
<div class="doctools">
<h1 class="doctools_title">tar(n) 0.14 tcllib &quot;Tar file handling&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>tar - Tar file creation, extraction &amp; manipulation</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">BEWARE</a></li>
<li class="doctools_section"><a href="#section3">COMMANDS</a></li>
<li class="doctools_section"><a href="#section4">Bugs, Ideas, Feedback</a></li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#category">Category</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">Tcl 8.5 9</b></li>
<li>package require <b class="pkgname">tar <span class="opt">?0.14?</span></b></li>
</ul>
<ul class="doctools_syntax">
<li><a href="#1"><b class="cmd">::tar::contents</b> <i class="arg">tarball</i> <span class="opt">?<b class="option">-chan</b>?</span> <span class="opt">?<b class="option">-gzip</b>?</span></a></li>
<li><a href="#2"><b class="cmd">::tar::stat</b> <i class="arg">tarball</i> <span class="opt">?file?</span> <span class="opt">?<b class="option">-chan</b>?</span> <span class="opt">?<b class="option">-gzip</b>?</span></a></li>
<li><a href="#3"><b class="cmd">::tar::untar</b> <i class="arg">tarball</i> <i class="arg">args</i></a></li>
<li><a href="#4"><b class="cmd">::tar::get</b> <i class="arg">tarball</i> <i class="arg">fileName</i> <span class="opt">?<b class="option">-chan</b>?</span> <span class="opt">?<b class="option">-gzip</b>?</span></a></li>
<li><a href="#5"><b class="cmd">::tar::create</b> <i class="arg">tarball</i> <i class="arg">files</i> <i class="arg">args</i></a></li>
Changes to installer.tcl.
290
291
292
293
294
295
296

297


298
299

300


301
302

303
304
305
306
307
308
309
	# tclkit. Detect this and derive the location from the
	# location of the executable itself for that case.

	if {[string match [info nameofexecutable]* [info library]]} {
	    # Starkit
	    set libdir [file join [file dirname [file dirname [info nameofexecutable]]] lib]
	} else {

	    # Unwrapped.


	    if {[catch {set libdir [lindex $::tcl_pkgPath end]}]} {
		set libdir [file dirname [info library]]

	    }


	}


	set basedir [file dirname $libdir]
	set bindir  [file join $basedir bin]

	if {[string compare $tcl_platform(platform) windows] == 0} {
	    set mandir  {}
	    set htmldir [file join $basedir ${package_name}_doc]
	} else {







>

>
>
|
<
>
|
>
>
|
|
>







290
291
292
293
294
295
296
297
298
299
300
301

302
303
304
305
306
307
308
309
310
311
312
313
314
315
	# tclkit. Detect this and derive the location from the
	# location of the executable itself for that case.

	if {[string match [info nameofexecutable]* [info library]]} {
	    # Starkit
	    set libdir [file join [file dirname [file dirname [info nameofexecutable]]] lib]
	} else {
	    puts "$::auto_path"
	    # Unwrapped.
	    foreach path $::auto_path {
		puts $path
		if {[string match "*zipfs:*" $path]} {

		    continue
		}
		set libdir $path
		break
	    }
	}
	puts "libdir is $libdir"
	set basedir [file dirname $libdir]
	set bindir  [file join $basedir bin]

	if {[string compare $tcl_platform(platform) windows] == 0} {
	    set mandir  {}
	    set htmldir [file join $basedir ${package_name}_doc]
	} else {
Changes to modules/math/ChangeLog.











1
2
3
4
5
6
7











2024-11-15  Arjen Markus <[email protected]>
        * elliptic.tcl: Correct the description of dn (pers.comm. K. Koehler)

2024-01-21  Arjen Markus <[email protected]>
        * statistics.test: Correct mistake with srand function (pers.comm. A. Kupries)

2024-01-15  Arjen Markus <[email protected]>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2025-02-09  Arjen Markus <[email protected]>
        * combinatoricsExt.tcl: Fix a typo (ticket e99fe133e61b7868a4c2f7d9c2e6cb2f164a7246)

2025-01-04  Arjen Markus <[email protected]>
        * filtergen.tcl: Replace the existing implementation by one based on an MIT license, add Chebyshev filters
        * filtergen.man: Document the new Chebyshev filters
        * filtergen.test: Added tests for the Chebyshev filters

2024-11-19  Arjen Markus <[email protected]>
        * statistics.tcl: Check if the x and y values for the linear model show variation

2024-11-15  Arjen Markus <[email protected]>
        * elliptic.tcl: Correct the description of dn (pers.comm. K. Koehler)

2024-01-21  Arjen Markus <[email protected]>
        * statistics.test: Correct mistake with srand function (pers.comm. A. Kupries)

2024-01-15  Arjen Markus <[email protected]>
Changes to modules/math/combinatoricsExt.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# combinatoricsExt.tcl --
#     Procedures for combinatorial functions and generating combinatorial collections
#
#     Note:
#     The older procedures factorial and choose assume Tcl 8.0, so no large integer support
#     The versions in this package, permutations and combinations, depend on Tcl 8.6 and later
#     for the large integer support and for TclOO.
#
#     Several parts based on: https://wiki.tcl-lang.org/page/Permutations and other Wiki pages
#
package require Tcl 8.6 9
package require TclOO
package provide math::combinatorics 2.1

# ::math::combinatorics --
#     Encompassing namespace and auxiliary variables
#
namespace eval ::math::combinatorics {
    variable factorial
    variable partition












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# combinatoricsExt.tcl --
#     Procedures for combinatorial functions and generating combinatorial collections
#
#     Note:
#     The older procedures factorial and choose assume Tcl 8.0, so no large integer support
#     The versions in this package, permutations and combinations, depend on Tcl 8.6 and later
#     for the large integer support and for TclOO.
#
#     Several parts based on: https://wiki.tcl-lang.org/page/Permutations and other Wiki pages
#
package require Tcl 8.6 9
package require TclOO
package provide math::combinatorics 2.1.1

# ::math::combinatorics --
#     Encompassing namespace and auxiliary variables
#
namespace eval ::math::combinatorics {
    variable factorial
    variable partition
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
        return 1
    }

    if { $n < [llength $factorial] } {
        return [lindex $factorial $n]
    }

    set newfactorial [lindex $$factorial end]

    for {set k [llength $factorial]} { $k <= $n} {incr k} {
        set newfactorial [expr {$newfactorial * $k}]
        lappend factorial $newfactorial
    }

    return $newfactorial







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
        return 1
    }

    if { $n < [llength $factorial] } {
        return [lindex $factorial $n]
    }

    set newfactorial [lindex $factorial end]

    for {set k [llength $factorial]} { $k <= $n} {incr k} {
        set newfactorial [expr {$newfactorial * $k}]
        lappend factorial $newfactorial
    }

    return $newfactorial
Changes to modules/math/filtergen.man.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19






20
21
22
23
24
25
26
27
28
29
30

31






32
33

34

35




36
37






38
39
40
41
42

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[comment {-*- tcl -*- doctools manpage}]
[vset VERSION 0.3]
[manpage_begin math::filters n [vset VERSION]]
[keywords digital]
[keywords filtering]
[copyright {2020 by Arjen Markus}]
[moddesc   {Tcl Math Library}]
[titledesc {Digital filters}]
[category  Mathematics]
[require Tcl "8.6 9"]
[require TclOO]
[require math::filters [opt [vset VERSION]]]

[description]
[para]
The [package math::filters] package implements digital filters,
notably Butterworth low-pass and high-pass filters. The procedures
allow to filter an entire data series as well as filter data one
by one.








[section "PROCEDURES"]

The package defines the following public procedures:

[list_begin definitions]

[call [cmd ::math::filters::filterButterworth] [arg lowpass] [arg order] [arg samplefreq] [arg cutofffreq]]

Determine the coefficients for a Butterworth filter of given order. The coefficients are returned as

a list of the x-coefficients, the y-coefficients and the scale. The formula is (n is the filter order):






[example {
                   n             n

    scale * y_k = sum x_(k-i) + sum y_(k-i)

                  i=0           i=1




}]







[list_begin arguments]
[arg_def bool lowpass] Generate a low-pass filter (1) or a high-pass filter (0)
[arg_def integer lowpass] The order of the filter to be generated
[arg_def double samplefreq] Sampling frequency of the data series
[arg_def double cutofffreq] Cut-off frequency for the filter

[list_end]


[call [cmd ::math::filters::filter] [arg coeffs] [arg data]]

Filter the entire data series based on the filter coefficients.

[list_begin arguments]
[arg_def list coeffs] List of coefficients as generated by [emph filterButterworth] (or in fact any similar list of coefficients)
[arg_def list data] Data to be filtered
[list_end]


[call [cmd ::math::filters::filterObj] new [arg coeffs] [arg yinit]]

Create a filter object. The initial x data are taken as zero. The initial y data can be prescribed. If they are not given,
they are taken as zero as well.

[list_begin arguments]
[arg_def list coeffs] List of coefficients as generated by [emph filterButterworth] (or in fact any similar list of coefficients)
[arg_def list yinit] (Optional) initial data for the filter result.

|














|


>
>
>
>
>
>










|
>
|
>
>
>
>
>
>
|
|
>
|
>
|
>
>
>
>
|

>
>
>
>
>
>


|

|
>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
[comment {-*- tcl -*- doctools manpage}]
[vset VERSION 0.4]
[manpage_begin math::filters n [vset VERSION]]
[keywords digital]
[keywords filtering]
[copyright {2020 by Arjen Markus}]
[moddesc   {Tcl Math Library}]
[titledesc {Digital filters}]
[category  Mathematics]
[require Tcl "8.6 9"]
[require TclOO]
[require math::filters [opt [vset VERSION]]]

[description]
[para]
The [package math::filters] package implements digital filters,
notably Butterworth and Chebyshev low-pass and high-pass filters. The procedures
allow to filter an entire data series as well as filter data one
by one.

Note: [uri https://en.wikipedia.org/wiki/Digital_filter] and other pages on Wikipedia describe
the principles and design considerations of these digital filters.

Note: This is a reimplementation compared to version 0.3, which was based on GPL-licensed code.
One possible incompatibility with that version is that the order now needs to be even.


[section "PROCEDURES"]

The package defines the following public procedures:

[list_begin definitions]

[call [cmd ::math::filters::filterButterworth] [arg lowpass] [arg order] [arg samplefreq] [arg cutofffreq]]

Determine the coefficients for a Butterworth filter of given (even) order. The coefficients are returned as
a nested list, suitable for the [term filter] command or method,

[list_begin arguments]
[arg_def bool lowpass] Generate a low-pass filter (1) or a high-pass filter (0)
[arg_def integer order] The order of the filter to be generated - it must be even
[arg_def double samplefreq] Sampling frequency of the data series
[arg_def double cutofffreq] Cut-off frequency for the filter (at most half the sampling frequency)
[list_end]


[call [cmd ::math::filters::filter] [arg coeffs] [arg data]]

Filter the entire data series based on the filter coefficients.

[list_begin arguments]
[arg_def list coeffs] List of coefficients as generated by [emph filterButterworth] (or in fact any similar list of coefficients)
[arg_def list data] Data to be filtered
[list_end]


[call [cmd ::math::filters::filterChebyshev] [arg lowpass] [arg order] [arg samplefreq] [arg cutofffreq] [opt [arg epsilon]]]

Determine the coefficients for a Chebyshev filter of given (even) order. The coefficients are returned as
a nested list, suitable for the [term filter] command or method, For this type of filters an extra parameter
can be given, the so-called ripple factor. This controls the smoothness of the gain factor.

[list_begin arguments]
[arg_def bool lowpass] Generate a low-pass filter (1) or a high-pass filter (0)
[arg_def integer order] The order of the filter to be generated - it must be even
[arg_def double samplefreq] Sampling frequency of the data series
[arg_def double cutofffreq] Cut-off frequency for the filter (must be less than half the sampling frequency)
[arg_def double epsilon] Ripple factor, defaults to 0.1
[list_end]


[call [cmd ::math::filters::filter] [arg coeffs] [arg data]]

Filter the entire data series based on the filter coefficients.

[list_begin arguments]
[arg_def list coeffs] List of coefficients as generated by [emph filterButterworth] (or in fact any similar list of coefficients)
[arg_def list data] Data to be filtered
[list_end]


[call [cmd ::math::filters::filterObject] new [arg coeffs] [arg yinit]]

Create a filter object. The initial x data are taken as zero. The initial y data can be prescribed. If they are not given,
they are taken as zero as well.

[list_begin arguments]
[arg_def list coeffs] List of coefficients as generated by [emph filterButterworth] (or in fact any similar list of coefficients)
[arg_def list yinit] (Optional) initial data for the filter result.
Changes to modules/math/filtergen.tcl.
1
2
3
4


5
6
7
8
9
10

11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63



















































64
65
66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227



228
229
230
231
232
233
234
235
236
237
238
239


240
241
242
243
244
245
246
247
248
249
250
251
# filtergen.tcl --
#     Package for digital filters
#     filterButterworth:
#         Generate the coefficients for a low-pass or high-pass Butterworth filter


#     filter:
#         Filter an entire series of data
#     filterObject:
#         Class to create filters
#
#     Derived from: https://www.meme.net.au/butterworth.html

#
#     Here is the license notice from this webpage:

#
#       @licstart  The following is the entire license notice for the
#       JavaScript code in this page.
#
#       Copyright (C) 2013 Glenn McIntosh
#
#       The JavaScript code in this page is free software: you can
#       redistribute it and/or modify it under the terms of the GNU
#       General Public License (GNU GPL) as published by the Free Software
#       Foundation, either version 3 of the License, or (at your option)
#       any later version.  The code is distributed WITHOUT ANY WARRANTY;
#       without even the implied warranty of MERCHANTABILITY or FITNESS
#       FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
#
#       As additional permission under GNU GPL version 3 section 7, you
#       may distribute non-source (e.g., minimized or compacted) forms of
#       that code without the copy of the GNU GPL normally required by
#       section 4, provided you include this license notice and a URL
#       through which recipients can access the Corresponding Source.
#
#       @licend  The above is the entire license notice
#       for the JavaScript code in this page.
#
package require Tcl 8.6 9
package require TclOO

namespace eval ::math::filters {}

# filterButterworth --
#     Generate the coefficients for a low-pass/high-pass Butterworth filter
#
# Arguments:
#     lowpass              Low-pass if 1, high-pass if 0
#     order                Order of the filter
#     samplefreq           Sample frequency
#     cutofffreq           Cut-off frequency (3 dB point)
#
# Returns:
#     List (nexted list) of coefficients for x and y and the scale factor
#
proc ::math::filters::filterButterworth {lowpass order samplefreq cutofffreq} {

    ##nagelfar ignore
    if { ![string is integer $order] || $order <= 0 } {
        return -code error "The order must be a positive integer"
    }
    if { $samplefreq <= 0.0 || $cutofffreq <= 0.0 } {
        return -code error "The frequencies must be positive"
    }
    if { $samplefreq < $cutofffreq } {
        return -code error "The cutoff frequency must be lower than the sample frequency"



















































    }

    set pi     [expr {acos(-1.0)}]
    set cutoff [expr {-$cutofffreq / double($samplefreq) * 2.0 * $pi}]

    set yf0    [lrepeat [expr {$order+1}] 0.0]
    set yf1    $yf0
    set xf     $yf0

    lset yf0   0 -1.0
    lset yf1   0  0.0
    lset xf    0  1.0


    set scale  1.0
    set invert [expr {$lowpass == 1? 1.0 : -1.0}]

    for {set i 1} {$i <= $order} {incr i} {
        set angle  [expr {($i-0.5) / $order * $pi}]
        set sinsin [expr {1.0 - sin($cutoff) * sin($angle)}]
        set rcof0  [expr {-cos($cutoff) / $sinsin}]
        set rcof1  [expr { sin($cutoff) * cos($angle) / $sinsin}]

        lset yf0 $i 0.0
        lset yf1 $i 0.0

        for {set j $i} {$j > 0} {incr j -1} {
            set yf0jm1 [lindex $yf0 [expr {$j-1}]]
            set yf1jm1 [lindex $yf1 [expr {$j-1}]]
            set yf0j   [lindex $yf0 $j]
            set yf1j   [lindex $yf1 $j]

            lset yf0 $j [expr {$yf0j + $rcof0 * $yf0jm1 + $rcof1 * $yf1jm1}]
            lset yf1 $j [expr {$yf1j + $rcof0 * $yf1jm1 - $rcof1 * $yf0jm1}]
        }

        set  scale [expr {$scale * $sinsin * 2.0 / (1.0 - cos($cutoff) * $invert)}]
        set  xfim1 [lindex $xf [expr {$i-1}]]
        lset xf $i [expr {$xfim1 * $invert * ($order-$i+1)/double($i)}]
    }

    set scale [expr {sqrt($scale)}]

    for {set i 1} {$i <= $order} {incr i} {
        set  yf0i   [lindex $yf0 $i]
        lset yf0 $i [expr {$yf0i * $scale}]
    }

    return [list $xf [lrange $yf0 1 end] $scale]
}

# filter --
#     Filter the data series based on the given coefficients
#
# Arguments:
#     coeff           Filter coefficients, as generated by filtergen
#     data            Data to be filtered
#
# Returns:
#     The filtered data
#
# Note:
#     The initial part of the filtered data is a list of zeroes
#
proc ::math::filters::filter {coeff data} {
    lassign $coeff xcoeff ycoeff scale

    set filtered {}

    set yv [lrepeat [llength $ycoeff] [expr {0.0}]]

    set noxcoeff [llength $xcoeff]
    set xcoeff   [lreverse $xcoeff]
    set ycoeff   [lreverse $ycoeff]

    for {set i 0} {$i <= [llength $data]-$noxcoeff} {incr i} {
        set xv [lrange $data $i [expr {$i+$noxcoeff-1}]]

        set f  [expr {0.0}]


        foreach x $xv c $xcoeff {
            set f [expr {$f + $c * $x}]
        }

        foreach y $yv c $ycoeff {
            set f [expr {$f + $c * $y}]

        }

        set f [expr {$f / $scale}]

        lappend filtered $f

        set yv [concat [lrange $yv 1 end] $f]
    }

    return $filtered
}

# filterObject --
#     Create an object that can filter incoming data
#
# Arguments:
#     coeff           Filter coefficients, as generated by filtergen


#     yinit           (Optional) initial y-values
#
::oo::class create ::math::filters::filterObject {
    variable xcoeff
    variable ycoeff
    variable yv
    variable xv
    variable xv_org
    variable yv_org

    #
    # Constructor:
    # - the arguments coeff and, optionally, yinit
    # - prepare everything
    #
    constructor {coeff {yinit {}}} {
        variable xcoeff
        variable ycoeff
        variable scale
        variable yv
        variable xv
        variable yv_org
        variable xv_org

        lassign $coeff xcoeff ycoeff scale

        set xcoeff   [lreverse $xcoeff]
        set ycoeff   [lreverse $ycoeff]

        if { $yinit eq {} } {
            set yv [lrepeat [llength $ycoeff] [expr {0.0}]]
        } else {
            if { [llength $yinit] != [llength $ycoeff] } {
                return -code error "Length of initial y-values must be equal to the number of y coefficients"
            }
            set yv $yinit
        }
        set xv [lrepeat [llength $xcoeff] [expr {0.0}]]

        set xv_org $xv
        set yv_org $yv
    }

    method filter {x} {
        variable xcoeff
        variable ycoeff
        variable scale
        variable yv
        variable xv

        set xv [concat [lrange $xv 1 end] $x]
        set f  [expr {0.0}]

        foreach x $xv c $xcoeff {
            set f [expr {$f + $c * $x}]
        }

        foreach y $yv c $ycoeff {
            set f [expr {$f + $c * $y}]
        }

        set f  [expr {$f / $scale}]




        set yv [concat [lrange $yv 1 end] $f]

        return $f
    }

    method reset {} {
        variable yv
        variable xv
        variable xv_org
        variable yv_org



        set xv $xv_org
        set yv $yv_org
    }
}

# Publish the package

namespace eval ::math::filters {
    namespace export filterButterworth filter filterObject
}

package provide math::filters 0.3




>
>





|
>

<
>

<
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















|




|
|




|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



<

|
|
<

|
|
<

>
|
|

|
<
<
<
<
|
<
<
|
<
|
|
<
<
|
<
<
<
|
<
|
<


|
|
<
<
<
|
|
<
















|



|
|
|
|
<

|
|

|
|
>
|
|
<
|
<
|
>


<
<
|
<
<










>
>
|











|


|
|
|
|
|
|
|
|
|
<

<
<
|
<
<
<
<
<
|
<
<
|
|
|
|



|
|
|
|
|
|
|
<
|
<
<
|
|
|
|
<
|
|
>
>
>
|
<

|



|
|
|
|

>
>
|
|









|
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16

17

18

















19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104

105
106
107

108
109
110
111
112
113




114


115

116
117


118



119

120

121
122
123
124



125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159

160

161
162
163
164


165


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201

202


203





204


205
206
207
208
209
210
211
212
213
214
215
216
217
218

219


220
221
222
223

224
225
226
227
228
229

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# filtergen.tcl --
#     Package for digital filters
#     filterButterworth:
#         Generate the coefficients for a low-pass or high-pass Butterworth filter
#     filterChebyshev:
#         Generate the coefficients for a low-pass or high-pass Chebyshev filter
#     filter:
#         Filter an entire series of data
#     filterObject:
#         Class to create filters
#
#     Derived from: https://github.com/adis300/filter-c, which has an MIT license
#     (Note: the original code had a small error, this has been corrected here)
#

#     More information on Chebyshev filters: https://en.wikipedia.org/wiki/Chebyshev_filter
#

#     Note:

#     We can implement band pass/stop filters from the same source.

















#
package require Tcl 8.6 9
package require TclOO

namespace eval ::math::filters {}

# filterButterworth --
#     Generate the coefficients for a low-pass/high-pass Butterworth filter
#
# Arguments:
#     lowpass              Low-pass if 1, high-pass if 0
#     order                Order of the filter
#     samplefreq           Sample frequency
#     cutofffreq           Cut-off frequency (3 dB point)
#
# Returns:
#     List (nested list) of coefficients for x and y and the scale factor
#
proc ::math::filters::filterButterworth {lowpass order samplefreq cutofffreq} {

    ##nagelfar ignore
    if { ![string is integer $order] || $order <= 0 || $order % 2 != 0 } {
        return -code error "The order must be an even positive integer"
    }
    if { $samplefreq <= 0.0 || $cutofffreq <= 0.0 } {
        return -code error "The frequencies must be positive"
    }
    if { $samplefreq < 2.0 * $cutofffreq } {
        return -code error "The cutoff frequency must be higher than half the sample frequency"
    }

    set pi     [expr {acos(-1.0)}]

    set a      [expr {tan($pi * $cutofffreq / $samplefreq)}]
    set a2     [expr {$a**2}]

    set s      [expr {1.0 * $samplefreq}]
    set order  [expr {$order / 2}]

    for {set i 0} {$i < $order} {incr i} {
        set r [expr {sin($pi * (2.0 * $i + 1.0) / (4.0 * $order))}]
        set s [expr {$a2 + 2.0 * $a * $r + 1.0}]
        lappend A  [expr {$a2 / $s}]
        lappend d1 [expr {2.0 * (1.0 - $a2) / $s}]
        lappend d2 [expr {-($a2 - 2.0 * $a * $r + 1.0) / $s}]
    }

    set coeffw1 [expr {$lowpass ? 2.0 : -2.0}]
    set scale   [expr {1.0}]

    return [list $coeffw1 $scale $A $d1 $d2]
}

# filterChebyshev --
#     Generate the coefficients for a low-pass/high-pass Chebyshev filter
#
# Arguments:
#     lowpass              Low-pass if 1, high-pass if 0
#     order                Order of the filter
#     samplefreq           Sample frequency
#     cutofffreq           Cut-off frequency (3 dB point)
#     epsilon              Ripple factor (defaults to 0.1)
#
# Returns:
#     List (nested list) of coefficients for x and y and the scale factor
#
proc ::math::filters::filterChebyshev {lowpass order samplefreq cutofffreq {epsilon 0.1}} {

    ##nagelfar ignore
    if { ![string is integer $order] || $order <= 0 || $order % 2 != 0 } {
        return -code error "The order must be an even positive integer"
    }
    if { $samplefreq <= 0.0 || $cutofffreq <= 0.0 } {
        return -code error "The frequencies must be positive"
    }
    if { $samplefreq < 2.0 * $cutofffreq } {
        return -code error "The cutoff frequency must be higher than half the sample frequency"
    }
    if { $epsilon <= 0.0 } {
        return -code error "The ripple factor should be positive"
    }

    set pi     [expr {acos(-1.0)}]


    set a      [expr {tan($pi * $cutofffreq / $samplefreq)}]
    set a2     [expr {$a**2}]


    set s      [expr {1.0 * $samplefreq}]
    set order  [expr {$order / 2}]


    set u      [expr {log((1.0 + sqrt(1.0 + $epsilon**2)) / $epsilon)}]
    set cu     [expr {cosh($u / (2.0 * $order))}]
    set su     [expr {sinh($u / (2.0 * $order))}]

    for {set i 0} {$i < $order} {incr i} {




        set b [expr {sin($pi * (2.0 * $i + 1.0) / (4.0 * $order)) * $su}]


        set c [expr {cos($pi * (2.0 * $i + 1.0) / (4.0 * $order)) * $cu}]

        set c [expr {$b**2 + $c**2}]
        set s [expr {$a2 * $c + 2.0 * $a * $b + 1.0}]


        lappend A  [expr {$a2 / (4.0 * $s)}]



        lappend d1 [expr {2.0 * (1.0 - $a2 * $c) / $s}]

        lappend d2 [expr {-($a2 * $c - 2.0 * $a * $b + 1.0) / $s}]

    }

    set coeffw1 [expr {$lowpass ? 2.0 : -2.0}]
    set scale   [expr {2.0 / $epsilon}]




    return [list $coeffw1 $scale $A $d1 $d2]

}

# filter --
#     Filter the data series based on the given coefficients
#
# Arguments:
#     coeff           Filter coefficients, as generated by filtergen
#     data            Data to be filtered
#
# Returns:
#     The filtered data
#
# Note:
#     The initial part of the filtered data is a list of zeroes
#
proc ::math::filters::filter {coeff data} {
    lassign $coeff coeffw1 scale list_A list_d1 list_d2

    set filtered {}

    set n       [llength $list_A]
    set list_w0 [lrepeat $n [expr {0.0}]]
    set list_w1 $list_w0
    set list_w2 $list_w0


    for {set j 0} {$j < [llength $data]} {incr j} {
        set x [lindex $data $j]

        set i 0
        foreach A $list_A d1 $list_d1 d2 $list_d2 w1 $list_w1 w2 $list_w2 {
            set  w0 [expr {$d1 * $w1 + $d2 * $w2 + $x}]
            set  x  [expr {$A * ($w0 + $coeffw1 * $w1 + $w2)}]
            lset list_w0 $i $w0

            lset list_w2 $i $w1

            lset list_w1 $i $w0
            incr i
        }



        lappend filtered [expr {$scale * $x}]


    }

    return $filtered
}

# filterObject --
#     Create an object that can filter incoming data
#
# Arguments:
#     coeff           Filter coefficients, as generated by filtergen
#
# Note:
#     Dropping the optional initial values
#
::oo::class create ::math::filters::filterObject {
    variable xcoeff
    variable ycoeff
    variable yv
    variable xv
    variable xv_org
    variable yv_org

    #
    # Constructor:
    # - the arguments coeff as provided by the filter generator
    # - prepare everything
    #
    constructor {coeff} {
        variable coeffw1
        variable scale
        variable list_A
        variable list_d1
        variable list_d2
        variable list_w0
        variable list_w1
        variable list_w2




        lassign $coeff coeffw1 scale list_A list_d1 list_d2








        set n       [llength $list_A]
        set list_w0 [lrepeat $n [expr {0.0}]]
        set list_w1 $list_w0
        set list_w2 $list_w0
    }

    method filter {x} {
        variable coeffw1
        variable scale
        variable list_A
        variable list_d1
        variable list_d2
        variable list_w0
        variable list_w1

        variable list_w2



        set i 0
        foreach A $list_A d1 $list_d1 d2 $list_d2 w1 $list_w1 w2 $list_w2 {
            set  w0 [expr {$d1 * $w1 + $d2 * $w2 + $x}]

            set  x  [expr {$A * ($w0 + $coeffw1 * $w1 + $w2)}]
            lset list_w0 $i $w0
            lset list_w2 $i $w1
            lset list_w1 $i $w0
            incr i
        }


        return [expr {$scale * $x}]
    }

    method reset {} {
        variable list_A
        variable list_w0
        variable list_w1
        variable list_w2

        set n       [llength $list_A]
        set list_w0 [lrepeat $n [expr {0.0}]]
        set list_w1 $list_w0
        set list_w2 $list_w0
    }
}

# Publish the package

namespace eval ::math::filters {
    namespace export filterButterworth filter filterObject
}

package provide math::filters 0.4
Changes to modules/math/filtergen.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- tcl -*-
# Tests for filters library.
#
# RCS: @(#) $Id: geometry.test,v 1.13 2010/04/06 17:02:25 andreas_kupries Exp $

# -------------------------------------------------------------------------

source [file join \
	[file dirname [file dirname [file join [pwd] [info script]]]] \
	devtools testutilities.tcl]

testsNeedTcl     8.6
testsNeedTcltest 1.0

support {
    useLocal math.tcl math
}








|
|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- tcl -*-
# Tests for filters library.
#
# RCS: @(#) $Id: geometry.test,v 1.13 2010/04/06 17:02:25 andreas_kupries Exp $

# -------------------------------------------------------------------------

source [file join \
        [file dirname [file dirname [file join [pwd] [info script]]]] \
        devtools testutilities.tcl]

testsNeedTcl     8.6
testsNeedTcltest 1.0

support {
    useLocal math.tcl math
}
63
64
65
66
67
68
69
70
71
72
73
74

75









76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
































102
103
104
105
106
107
108
# -------------------------------------------------------------------------

# Butterworth filter coefficients

test butterworth-1.1 {low-pass, second order} -match numbers -body {
    set coeffs [::math::filters::filterButterworth 1 2 100 20]
    set result [concat {*}$coeffs]
} -result {1.0 2.0 1.0 1.78885 -0.94793 4.84093}

test butterworth-1.2 {high-pass, second order} -match numbers -body {
    set coeffs [::math::filters::filterButterworth 0 2 100 20]
    set result [concat {*}$coeffs]

} -result {1.0 -2.0 1.0 0.94427 -0.50038 2.55535}











# Actually filter data

# 20 data, second-order filter, so 18 data returned
test filter-1.0 {low-pass, second order, uniform series} -match numbers -body {
    set coeffs   [::math::filters::filterButterworth 1 2 100 20]
    set data     [lrepeat 20 1.0]
    set filtered [::math::filters::filter $coeffs $data]
    set result   [list [llength $filtered] [lindex $filtered end]]
} -result {18 1.0}

test filter-1.1 {low-pass, second order, sine series} -match numbers -body {
    set coeffs   [::math::filters::filterButterworth 1 2 100 20]

    set twopi  [expr {2.0 * acos(-1.0)}]
    set period 100

    set data {}

    for {set i 0} {$i < $period} {incr i} {
        lappend data [expr {cos($twopi * ($i/1.0) / double($period))}]
    }

    set filtered [lrange [::math::filters::filter $coeffs $data] end-7 end]
} -result {0.845195 0.877086 0.905515 0.930371 0.951555 0.968984 0.982588 0.992315}

































# The object interface

test filterobj-1.0 {low-pass, second order, sine series} -match numbers -body {
    set coeffs   [::math::filters::filterButterworth 1 2 100 20]
    set filter   [::math::filters::filterObject new $coeffs]








|




>
|
>
>
>
>
>
>
>
>
>




<
|




|

|













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# -------------------------------------------------------------------------

# Butterworth filter coefficients

test butterworth-1.1 {low-pass, second order} -match numbers -body {
    set coeffs [::math::filters::filterButterworth 1 2 100 20]
    set result [concat {*}$coeffs]
} -result {2.0 1.0 0.20657 0.36953 -0.195816}

test butterworth-1.2 {high-pass, second order} -match numbers -body {
    set coeffs [::math::filters::filterButterworth 0 2 100 20]
    set result [concat {*}$coeffs]
} -result {-2.0 1.0 0.20657 0.36953 -0.195816}

test chebyshev-1.1 {low-pass, second order} -match numbers -body {
    set coeffs [::math::filters::filterChebyshev 1 2 100 20]
    set result [concat {*}$coeffs]
} -result {2.0 20.0 0.022604 -0.566099 -0.251249}

test chebyshev-1.2 {high-pass, second order} -match numbers -body {
    set coeffs [::math::filters::filterChebyshev 0 2 100 20]
    set result [concat {*}$coeffs]
} -result {-2.0 20.0 0.022604 -0.566099 -0.251249}


# Actually filter data


test filter-1.0 {low-pass, second order, uniform series, Butterworth} -match numbers -body {
    set coeffs   [::math::filters::filterButterworth 1 2 100 20]
    set data     [lrepeat 20 1.0]
    set filtered [::math::filters::filter $coeffs $data]
    set result   [list [llength $filtered] [lindex $filtered end]]
} -result {20 1.0}

test filter-1.1 {low-pass, second order, sine series, Butterworth} -match numbers -body {
    set coeffs   [::math::filters::filterButterworth 1 2 100 20]

    set twopi  [expr {2.0 * acos(-1.0)}]
    set period 100

    set data {}

    for {set i 0} {$i < $period} {incr i} {
        lappend data [expr {cos($twopi * ($i/1.0) / double($period))}]
    }

    set filtered [lrange [::math::filters::filter $coeffs $data] end-7 end]
} -result {0.845195 0.877086 0.905515 0.930371 0.951555 0.968984 0.982588 0.992315}

test filter-2.1 {low-pass, second order, sine series, Chebyshev} -match numbers -body {
    set coeffs   [::math::filters::filterChebyshev 1 2 100 20]

    set twopi  [expr {2.0 * acos(-1.0)}]
    set period 50

    set data {}

    for {set i 0} {$i < $period} {incr i} {
        lappend data [expr {cos($twopi * ($i/1.0) / double($period))}]
    }

    set filtered [lrange [::math::filters::filter $coeffs $data] end-7 end]
} -result {0.488962 0.593742 0.68916 0.773708 0.846055 0.905059 0.94979 0.979541}


test filter-2.2 {high-pass, second order, sine series, Chebyshev} -match numbers -body {
    set coeffs   [::math::filters::filterChebyshev 0 2 500 200]

    set twopi  [expr {2.0 * acos(-1.0)}]
    set period 50

    set data {}

    for {set i 0} {$i < $period} {incr i} {
        lappend data [expr {cos($twopi * ($i/1.0) / double($period))}]
    }

    set filtered [lrange [::math::filters::filter $coeffs $data] end-7 end]
} -result {-0.00144136 -0.0025429 -0.0031529 -0.00260315 -0.004107 -0.0029269 -0.00449589 -0.00327216}


# The object interface

test filterobj-1.0 {low-pass, second order, sine series} -match numbers -body {
    set coeffs   [::math::filters::filterButterworth 1 2 100 20]
    set filter   [::math::filters::filterObject new $coeffs]

Changes to modules/math/pkgIndex.tcl.
28
29
30
31
32
33
34
35
if {![package vsatisfies [package require Tcl] 8.6 9]} {return}
package ifneeded math::exact             1.0.2 [list source [file join $dir exact.tcl]]
package ifneeded math::PCA               1.1   [list source [file join $dir pca.tcl]]
package ifneeded math::figurate          1.1   [list source [file join $dir figurate.tcl]]
package ifneeded math::filters           0.3   [list source [file join $dir filtergen.tcl]]
package ifneeded math::probopt           1.1   [list source [file join $dir probopt.tcl]]
package ifneeded math::changepoint       0.2   [list source [file join $dir changepoint.tcl]]
package ifneeded math::combinatorics     2.1   [list source [file join $dir combinatoricsExt.tcl]]







|
28
29
30
31
32
33
34
35
if {![package vsatisfies [package require Tcl] 8.6 9]} {return}
package ifneeded math::exact             1.0.2 [list source [file join $dir exact.tcl]]
package ifneeded math::PCA               1.1   [list source [file join $dir pca.tcl]]
package ifneeded math::figurate          1.1   [list source [file join $dir figurate.tcl]]
package ifneeded math::filters           0.3   [list source [file join $dir filtergen.tcl]]
package ifneeded math::probopt           1.1   [list source [file join $dir probopt.tcl]]
package ifneeded math::changepoint       0.2   [list source [file join $dir changepoint.tcl]]
package ifneeded math::combinatorics     2.1.1 [list source [file join $dir combinatoricsExt.tcl]]
Changes to modules/math/statistics.tcl.
998
999
1000
1001
1002
1003
1004




1005
1006
1007
1008
1009
1010
1011
1012





1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026

   set sumx  0.0
   set sumy  0.0
   set sumx2 0.0
   set sumy2 0.0
   set sumxy 0.0
   set df    0




   foreach x $xdata y $ydata {
      if { $x != "" && $y != "" } {
         set sumx  [expr {$sumx+$x}]
         set sumy  [expr {$sumy+$y}]
         set sumx2 [expr {$sumx2+$x*$x}]
         set sumy2 [expr {$sumy2+$y*$y}]
         set sumxy [expr {$sumxy+$x*$y}]
         incr df





      }
   }

   if { $df <= 2 } {
      return -code error -errorcode ARG "$TOOFEWDATA: too few valid data"
   }
   if { $sumx2 == 0.0 } {
      return -code error -errorcode ARG "$TOOFEWDATA: independent values are all the same"
   }

   #
   # Calculate the intermediate quantities
   #
   set sx  [expr {$sumx2-$sumx*$sumx/$df}]







>
>
>
>








>
>
>
>
>






|







998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035

   set sumx  0.0
   set sumy  0.0
   set sumx2 0.0
   set sumy2 0.0
   set sumxy 0.0
   set df    0
   set minx  [expr {Inf}]
   set miny  [expr {Inf}]
   set maxx  [expr {-Inf}]
   set maxy  [expr {-Inf}]
   foreach x $xdata y $ydata {
      if { $x != "" && $y != "" } {
         set sumx  [expr {$sumx+$x}]
         set sumy  [expr {$sumy+$y}]
         set sumx2 [expr {$sumx2+$x*$x}]
         set sumy2 [expr {$sumy2+$y*$y}]
         set sumxy [expr {$sumxy+$x*$y}]
         incr df

         set minx  [expr {min($x,$minx)}]
         set miny  [expr {min($y,$miny)}]
         set maxx  [expr {max($x,$maxx)}]
         set maxy  [expr {max($y,$maxy)}]
      }
   }

   if { $df <= 2 } {
      return -code error -errorcode ARG "$TOOFEWDATA: too few valid data"
   }
   if { $minx == $maxx || $miny == $maxy } {
      return -code error -errorcode ARG "$TOOFEWDATA: independent values are all the same"
   }

   #
   # Calculate the intermediate quantities
   #
   set sx  [expr {$sumx2-$sumx*$sumx/$df}]
Changes to modules/tar/tar.man.
1
2
3
4
5
6
7
8
9
[comment {-*- mode: tcl ; fill-column: 80 -*- doctools manpage}]
[vset PACKAGE_VERSION 0.13]
[manpage_begin tar n [vset PACKAGE_VERSION]]
[keywords archive]
[keywords {tape archive}]
[keywords tar]
[moddesc   {Tar file handling}]
[titledesc {Tar file creation, extraction & manipulation}]
[category  {File formats}]

|







1
2
3
4
5
6
7
8
9
[comment {-*- mode: tcl ; fill-column: 80 -*- doctools manpage}]
[vset PACKAGE_VERSION 0.14]
[manpage_begin tar n [vset PACKAGE_VERSION]]
[keywords archive]
[keywords {tape archive}]
[keywords tar]
[moddesc   {Tar file handling}]
[titledesc {Tar file creation, extraction & manipulation}]
[category  {File formats}]
Changes to modules/tar/tar.tcl.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 2024    Christian Werner <[email protected]>
#                       (zlib support).
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require Tcl 8.5 9
package provide tar 0.13

# # ## ### ##### ######## ############# #####################
##
# Gzip support
#
# |Id  |Question            |Check                |Notes|
# |---:|:---                |:---                 |:---|







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 2024    Christian Werner <[email protected]>
#                       (zlib support).
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

package require Tcl 8.5 9
package provide tar 0.14

# # ## ### ##### ######## ############# #####################
##
# Gzip support
#
# |Id  |Question            |Check                |Notes|
# |---:|:---                |:---                 |:---|
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
	name mode uid gid size mtime cksum type \
	linkname magic version uname gname devmajor devminor prefix

    foreach x {name type linkname} {
        set $x [string trim [set $x] "\x00"]
    }
    foreach x {uid gid size mtime cksum} {
        set $x [format %d 0[string trim [set $x] " \x00"]]
    }
    set mode [string trim $mode " \x00"]

    if {$magic eq "ustar "} {
        # gnu tar
        # not fully supported
        foreach x {uname gname prefix} {
            set $x [string trim [set $x] "\x00"]
        }
        foreach x {devmajor devminor} {
            set $x [format %d 0[string trim [set $x] " \x00"]]
        }
    } elseif {$magic eq "ustar\x00"} {
        # posix tar
        foreach x {uname gname prefix} {
            set $x [string trim [set $x] "\x00"]
        }
        foreach x {devmajor devminor} {
            set $x [format %d 0[string trim [set $x] " \x00"]]
        }
    } else {
        # old style tar
        foreach x {uname gname devmajor devminor prefix} { set $x {} }
        if {$type eq ""} {
            if {[string match */ $name]} {
                set type 5







|










|







|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
	name mode uid gid size mtime cksum type \
	linkname magic version uname gname devmajor devminor prefix

    foreach x {name type linkname} {
        set $x [string trim [set $x] "\x00"]
    }
    foreach x {uid gid size mtime cksum} {
        set $x [format %d 0o0[string trim [set $x] " \x00"]]
    }
    set mode [string trim $mode " \x00"]

    if {$magic eq "ustar "} {
        # gnu tar
        # not fully supported
        foreach x {uname gname prefix} {
            set $x [string trim [set $x] "\x00"]
        }
        foreach x {devmajor devminor} {
            set $x [format %d 0o0[string trim [set $x] " \x00"]]
        }
    } elseif {$magic eq "ustar\x00"} {
        # posix tar
        foreach x {uname gname prefix} {
            set $x [string trim [set $x] "\x00"]
        }
        foreach x {devmajor devminor} {
            set $x [format %d 0o0[string trim [set $x] " \x00"]]
        }
    } else {
        # old style tar
        foreach x {uname gname devmajor devminor prefix} { set $x {} }
        if {$type eq ""} {
            if {[string match */ $name]} {
                set type 5
Changes to modules/tar/tar.test.
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136












137
138
139
} -body {
    string trim [tar::get $tarfile 02]
} -cleanup {
    cleanup-tkt-9f4c0e3e95
    unset tarfile
} -result {zero-two}

test tar-tkt-9f4c0e3e95-1.1 {Ticket 9f4c0e3e95, B, } -setup {
    set tarfile [setup-tkt-9f4c0e3e95]
} -body {
    tar::get $tarfile 0b10
} -cleanup {
    cleanup-tkt-9f4c0e3e95
    unset tarfile
} -returnCodes error -result {Tar "tartest/t.tar": File "0b10" not found}













# -------------------------------------------------------------------------
testsuiteCleanup







|







>
>
>
>
>
>
>
>
>
>
>
>



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
} -body {
    string trim [tar::get $tarfile 02]
} -cleanup {
    cleanup-tkt-9f4c0e3e95
    unset tarfile
} -result {zero-two}

test tar-tkt-9f4c0e3e95-1.1 {Ticket 9f4c0e3e95, B} -setup {
    set tarfile [setup-tkt-9f4c0e3e95]
} -body {
    tar::get $tarfile 0b10
} -cleanup {
    cleanup-tkt-9f4c0e3e95
    unset tarfile
} -returnCodes error -result {Tar "tartest/t.tar": File "0b10" not found}

# -------------------------------------------------------------------------

test tar-tkt-b01462dff7-1.0 {Ticket b01462dff7} -setup {
    set tarfile [localPath tests/b01462dff7.tar]
} -body {
    tar::untar $tarfile ; set _ "" ;# squash and ignore untar result
} -cleanup {
    # remove the extracted files
    file delete cp.html fields.c grammar.lsp sum xargs.1
    unset tarfile _
} -result {}

# -------------------------------------------------------------------------
testsuiteCleanup
Added modules/tar/tests/b01462dff7.tar.

cannot compute difference between binary files