line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
=head1 NAME
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
Math::PRBS - Generate Pseudorandom Binary Sequences using an Iterator-based Linear Feedback Shift Register
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
=cut
|
6
|
|
|
|
|
|
|
package Math::PRBS;
|
7
|
7
|
|
|
7
|
|
115746
|
use warnings;
|
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
248
|
|
8
|
7
|
|
|
7
|
|
32
|
use strict;
|
|
7
|
|
|
|
|
10
|
|
|
7
|
|
|
|
|
186
|
|
9
|
|
|
|
|
|
|
|
10
|
7
|
|
|
7
|
|
3508
|
use version 0.77; our $VERSION = version->declare('0.002');
|
|
7
|
|
|
|
|
12414
|
|
|
7
|
|
|
|
|
42
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
use Math::PRBS;
|
15
|
|
|
|
|
|
|
my $x3x2 = Math::PRBS->new( taps => [3,2] );
|
16
|
|
|
|
|
|
|
my $prbs7 = Math::PRBS->new( prbs => 7 );
|
17
|
|
|
|
|
|
|
my ($i, $value) = $x3x2t->next();
|
18
|
|
|
|
|
|
|
my @p7 = $prbs7->generate_all();
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
This module will generate various Pseudorandom Binary Sequences (PRBS). This module creates a iterator object, and you can use that object to generate the sequence one value at a time, or I.
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
The generated sequence is a series of 0s and 1s which appears random for a certain length, and then repeats thereafter.
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
It is implemented using an XOR-based Linear Feedback Shift Register (LFSR), which is described using a feedback polynomial (or reciprocal characteristic polynomial). The terms that appear in the polynomial are called the 'taps', because you tap off of that bit of the shift register for generating the feedback for the next value in the sequence.
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 FUNCTIONS AND METHODS
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head2 Initialization
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=over
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=item C<$seq = Math::PRBS::new( I value> )>
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
Creates the sequence iterator C<$seq> using one of the C value> pairs described below.
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=cut
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub new {
|
41
|
25
|
|
|
25
|
1
|
3918
|
my $class = shift;
|
42
|
25
|
|
|
|
|
111
|
my $self = bless { lfsr => 0, start => 0, i => 0, period => undef, taps => [] }, $class;
|
43
|
25
|
|
|
|
|
27
|
my %pairs;
|
44
|
25
|
100
|
|
|
|
94
|
%pairs = @_%2 ? () : @_;
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=over
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=item C I>
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
C needs an integer I to indicate one of the "standard" PRBS polynomials.
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# example: PRBS7 = x**7 + x**6 + 1
|
53
|
|
|
|
|
|
|
$seq = Math::PRBS::new( ptbs => 7 );
|
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
The "standard" PRBS polynomials implemented are
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
polynomial | prbs | taps | poly (string)
|
58
|
|
|
|
|
|
|
------------------+------------+-----------------+---------------
|
59
|
|
|
|
|
|
|
x**7 + x**6 + 1 | prbs => 7 | taps => [7,6] | poly => '1100000'
|
60
|
|
|
|
|
|
|
x**15 + x**14 + 1 | prbs => 15 | taps => [15,14] | poly => '110000000000000'
|
61
|
|
|
|
|
|
|
x**23 + x**18 + 1 | prbs => 23 | taps => [23,18] | poly => '10000100000000000000000'
|
62
|
|
|
|
|
|
|
x**31 + x**28 + 1 | prbs => 31 | taps => [31,28] | poly => '1001000000000000000000000000000'
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=cut
|
65
|
|
|
|
|
|
|
|
66
|
25
|
100
|
|
|
|
75
|
if( exists $pairs{prbs} )
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
67
|
|
|
|
|
|
|
{
|
68
|
5
|
|
|
|
|
27
|
my %prbs = (
|
69
|
|
|
|
|
|
|
7 => [7,6] ,
|
70
|
|
|
|
|
|
|
15 => [15,14],
|
71
|
|
|
|
|
|
|
23 => [23,18],
|
72
|
|
|
|
|
|
|
31 => [31,28],
|
73
|
|
|
|
|
|
|
);
|
74
|
5
|
100
|
|
|
|
26
|
die __PACKAGE__."::new(prbs => '$pairs{prbs}'): standard PRBS include 7, 15, 23, 31" unless exists $prbs{ $pairs{prbs} };
|
75
|
4
|
|
|
|
|
5
|
$self->{taps} = [ @{ $prbs{ $pairs{prbs} } } ];
|
|
4
|
|
|
|
|
19
|
|
76
|
|
|
|
|
|
|
}
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item C [ I, I, ... ]>
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
C needs an array reference containing the powers in the polynomial that you tap off for creating the feedback. Do I include the C<0> for the C in the polynomial; that's automatically included.
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# example: x**3 + x**2 + 1
|
83
|
|
|
|
|
|
|
# 3 and 2 are taps, 1 is not tapped, 0 is implied feedback
|
84
|
|
|
|
|
|
|
$seq = Math::PRBS::new( taps => [3,2] );
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=cut
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
elsif( exists $pairs{taps} )
|
89
|
|
|
|
|
|
|
{
|
90
|
9
|
100
|
|
|
|
41
|
die __PACKAGE__."::new(taps => $pairs{taps}): argument should be an array reference" unless 'ARRAY' eq ref($pairs{taps});
|
91
|
8
|
|
|
|
|
12
|
$self->{taps} = [ sort {$b <=> $a} @{ $pairs{taps} } ]; # taps in descending order
|
|
9
|
|
|
|
|
40
|
|
|
8
|
|
|
|
|
41
|
|
92
|
8
|
100
|
|
|
|
11
|
die __PACKAGE__."::new(taps => [@{$pairs{taps}}]): need at least one tap" unless @{ $pairs{taps} };
|
|
1
|
|
|
|
|
8
|
|
|
8
|
|
|
|
|
31
|
|
93
|
|
|
|
|
|
|
}
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=item C '...'>
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
C needs a string for the bits C downto C, with a 1 indicating the power is included in the list, and a 0 indicating it is not.
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# example: x**3 + x**2 + 1
|
100
|
|
|
|
|
|
|
# 3 and 2 are taps, 1 is not tapped, 0 is implied feedback
|
101
|
|
|
|
|
|
|
$seq = Math::PRBS::new( poly => '110' );
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=cut
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
elsif( exists $pairs{poly} )
|
106
|
|
|
|
|
|
|
{
|
107
|
9
|
|
|
|
|
11
|
local $_ = $pairs{poly}; # used for implicit matching in die-unless and while-condition
|
108
|
9
|
100
|
|
|
|
49
|
die __PACKAGE__."::new(poly => '$pairs{poly}'): argument should be an binary string" unless /^[01]*$/;
|
109
|
7
|
|
|
|
|
11
|
my @taps = ();
|
110
|
7
|
|
|
|
|
7
|
my $l = length;
|
111
|
7
|
|
|
|
|
23
|
while( m/([01])/g ) {
|
112
|
21
|
100
|
|
|
|
73
|
push @taps, $l - pos() + 1 if $1;
|
113
|
|
|
|
|
|
|
}
|
114
|
7
|
|
|
|
|
18
|
$self->{taps} = [ reverse sort {$a <=> $b} @taps ];
|
|
6
|
|
|
|
|
19
|
|
115
|
7
|
100
|
|
|
|
28
|
die __PACKAGE__."::new(poly => '$pairs{poly}'): need at least one tap" unless @taps;
|
116
|
|
|
|
|
|
|
} else {
|
117
|
2
|
|
|
|
|
22
|
die __PACKAGE__."::new(".join(',',@_)."): unknown arguments";
|
118
|
|
|
|
|
|
|
}
|
119
|
|
|
|
|
|
|
|
120
|
17
|
|
|
|
|
70
|
$self->{lfsr} = oct('0b1' . '0'x($self->{taps}[0] - 1));
|
121
|
17
|
|
|
|
|
25
|
$self->{start} = $self->{lfsr};
|
122
|
|
|
|
|
|
|
|
123
|
17
|
|
|
|
|
50
|
return $self;
|
124
|
|
|
|
|
|
|
}
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
=back
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item C<$seq-Ereset()>
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Reinitializes the sequence: resets the sequence back to the starting state. The next call to C will be the initial C<$i,$value> again.
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub reset {
|
135
|
14
|
|
|
14
|
1
|
23
|
my $self = shift;
|
136
|
14
|
|
|
|
|
32
|
$self->{lfsr} = $self->{start};
|
137
|
14
|
|
|
|
|
21
|
$self->{i} = 0;
|
138
|
14
|
|
|
|
|
19
|
return $self;
|
139
|
|
|
|
|
|
|
}
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=back
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head2 Iteration
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=over
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item C<$value = $seq-Enext()>
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=item C<($i, $value) = $seq-Enext()>
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
Computes the next value in the sequence. (Optionally, in list context, also returns the current value of the i for the sequence.)
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=cut
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub next {
|
156
|
771085
|
|
|
771085
|
1
|
502222
|
my $self = shift;
|
157
|
771085
|
|
|
|
|
446680
|
my $newbit = 0;
|
158
|
771085
|
|
|
|
|
849870
|
my $mask = oct( '0b' . '1'x($self->{taps}[0]) );
|
159
|
771085
|
|
|
|
|
517027
|
my $i = $self->{i};
|
160
|
771085
|
|
|
|
|
471046
|
++ $self->{i};
|
161
|
|
|
|
|
|
|
|
162
|
771085
|
|
|
|
|
434629
|
$newbit ^= ( $self->{lfsr} >> ($_-1) ) & 1 for @{ $self->{taps} };
|
|
771085
|
|
|
|
|
1481574
|
|
163
|
|
|
|
|
|
|
|
164
|
771085
|
|
|
|
|
640207
|
$self->{lfsr} = (($self->{lfsr} << 1) | $newbit) & $mask;
|
165
|
|
|
|
|
|
|
|
166
|
771085
|
100
|
100
|
|
|
2591422
|
$self->{period} = $i+1 if $i && !defined($self->{period}) && ($self->{lfsr} eq $self->{start});
|
|
|
|
100
|
|
|
|
|
167
|
|
|
|
|
|
|
|
168
|
771085
|
100
|
|
|
|
1531761
|
return wantarray ? ( $i , $newbit ) : $newbit;
|
169
|
|
|
|
|
|
|
}
|
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item C<$seq-Erewind()>
|
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
Rewinds the sequence back to the starting state. The subsequent call to C will be the initial C<$i,$value> again.
|
174
|
|
|
|
|
|
|
(This is actually an alias for C).
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=cut
|
177
|
|
|
|
|
|
|
|
178
|
7
|
|
|
7
|
|
5545
|
BEGIN { *rewind = \&reset; } # alias
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=item C<$i = $seq-Etell_i()>
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Return the current C position. The subsequent call to C will return this C.
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=cut
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub tell_i {
|
187
|
27
|
|
|
27
|
1
|
4344
|
return $_[0]->{i};
|
188
|
|
|
|
|
|
|
}
|
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item C<$state = $seq-Etell_state()>
|
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Return the current internal state of the feedback register. Useful for debug, or plugging into C<-Eseek_to_state($state)> to get back to this state at some future point in the program.
|
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub tell_state {
|
197
|
21
|
|
|
21
|
1
|
87
|
return $_[0]->{lfsr};
|
198
|
|
|
|
|
|
|
}
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item C<$seq-Eseek_to_i( $n )>
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=item C<$seq-Eith( $n )>
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
Moves forward in the sequence until C reaches C<$n>. If C $n> already, will internally C first. If C<$n E period>, it will stop at the end of the period, instead.
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=cut
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub seek_to_i {
|
209
|
10
|
|
|
10
|
1
|
38
|
my $self = shift;
|
210
|
10
|
|
|
|
|
16
|
my $n = shift;
|
211
|
|
|
|
|
|
|
|
212
|
10
|
100
|
|
|
|
55
|
$self->rewind() if $self->{i} > $n;
|
213
|
10
|
|
100
|
|
|
144
|
$self->next() while(($self->{i} < $n) && !(defined($self->{period}) && ($self->{i} >= $self->{period})));
|
|
|
|
100
|
|
|
|
|
214
|
|
|
|
|
|
|
}
|
215
|
|
|
|
|
|
|
|
216
|
7
|
|
|
7
|
|
12736
|
BEGIN { *ith = \&seek_to_i; } # alias
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=item C<$seq-Eseek_to_state( $lfsr )>
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
Moves forward in the sequence until the internal LFSR state reaches C<$lfsr>. It will wrap around, if necessary, but will stop once the internal state returns to the starting point.
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=cut
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub seek_to_state {
|
225
|
3
|
|
|
3
|
1
|
6
|
my $self = shift;
|
226
|
3
|
|
|
|
|
5
|
my $lfsr = shift;
|
227
|
3
|
|
|
|
|
6
|
my $state = $self->{lfsr};
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
#local $\ = "\n";
|
230
|
|
|
|
|
|
|
#local $, = "\t";
|
231
|
|
|
|
|
|
|
#print STDERR __LINE__, "seek_to_state($lfsr):", $self->{i}, $self->{lfsr};
|
232
|
3
|
100
|
|
|
|
13
|
$self->next() unless $state == $lfsr;
|
233
|
|
|
|
|
|
|
#print STDERR __LINE__, "seek_to_state($lfsr):", $self->{i}, $self->{lfsr};
|
234
|
3
|
|
100
|
|
|
27
|
$self->next() while ($self->{lfsr} != $lfsr) && ($self->{lfsr} != $state); # Devel::Cover = the coverage hole is because I am testing for a condition that shouldn't be possible: getting back to initial state without ever having
|
235
|
|
|
|
|
|
|
#print STDERR __LINE__, "seek_to_state($lfsr):", $self->{i}, $self->{lfsr};
|
236
|
|
|
|
|
|
|
}
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=item C<$seq-Eseek_forward_n( $n )>
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Moves forward in the sequence C<$n> steps.
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=cut
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
sub seek_forward_n {
|
245
|
4
|
|
|
4
|
1
|
11
|
my $self = shift;
|
246
|
4
|
|
|
|
|
5
|
my $n = shift;
|
247
|
|
|
|
|
|
|
|
248
|
4
|
|
|
|
|
20
|
$self->next() for 1 .. $n;
|
249
|
|
|
|
|
|
|
}
|
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=item C<$seq-Eseek_to_end()>
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=item C<$seq-Eseek_to_end( limit =E $n )>
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Moves forward until it's reached the end of the the period. (Will start in the first period using C.)
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
If C $n> is used, will not seek beyond C.
|
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=cut
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub seek_to_end {
|
262
|
7
|
|
|
7
|
1
|
12
|
my $self = shift;
|
263
|
|
|
|
|
|
|
|
264
|
7
|
100
|
|
|
|
37
|
die __PACKAGE__."::generate_to_end(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
|
265
|
|
|
|
|
|
|
|
266
|
6
|
|
|
|
|
27
|
my %opts = map lc, @_; # lowercase name,value pairs for canonical
|
267
|
6
|
100
|
|
|
|
18
|
my $limit = exists $opts{limit} ? $opts{limit} : 65535;
|
268
|
6
|
100
|
|
|
|
24
|
$limit = (2 ** $self->{taps}[0] - 1) if lc($limit) eq 'max';
|
269
|
6
|
100
|
100
|
|
|
39
|
$self->{i} %= $self->{period} if defined $self->{period} && $self->{i} > $self->{period};
|
270
|
6
|
|
|
|
|
22
|
while( $self->{i} % $limit ) {
|
271
|
245837
|
|
|
|
|
253385
|
$self->next();
|
272
|
245837
|
100
|
100
|
|
|
772766
|
$limit = $self->{period} if defined $self->{period} && $self->{period} < $limit; # pick PERIOD if PERIOD smaller than LIMIT
|
273
|
|
|
|
|
|
|
}
|
274
|
|
|
|
|
|
|
}
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=item C<@all = $seq-Egenerate( I )>
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
Generates the next I values in the sequence, wrapping around if it reaches the end. In list context, returns the values as a list; in scalar context, returns the string concatenating that list.
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=cut
|
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
sub generate {
|
283
|
4
|
|
|
4
|
1
|
1572
|
my ($self, $n) = @_;
|
284
|
4
|
|
|
|
|
6
|
my @ret = ();
|
285
|
4
|
|
|
|
|
10
|
foreach( 1 .. $n ) {
|
286
|
318
|
|
|
|
|
299
|
push @ret, scalar $self->next(); # need to force the scalar version to not push (i,value)
|
287
|
|
|
|
|
|
|
}
|
288
|
4
|
100
|
|
|
|
55
|
return wantarray ? @ret : join '', @ret;
|
289
|
|
|
|
|
|
|
}
|
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=item C<@all = $seq-Egenerate_all( )>
|
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=item C<@all = $seq-Egenerate_all( I $max_i> )>
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
Returns the whole sequence, from the beginning, up to the end of the sequence; in list context, returns the list of values; in scalar context, returns the string concatenating that list. If the sequence is longer than the default limit of 65535, or the limit given by C<$max_i> if the optional C $max_i> is provided, then it will stop before the end of the sequence.
|
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=item C<@all = $seq-Egenerate_to_end( )>
|
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=item C<@all = $seq-Egenerate_to_end( I $max_i> )>
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
Returns the remaining sequence, from whatever state the list is currently at, up to the end of the sequence; in list context, returns the list of values; in scalar context, returns the string concatenating that list. The limits work just as with C.
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=cut
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub generate_to_end {
|
306
|
18
|
|
|
18
|
1
|
496
|
my $self = shift;
|
307
|
|
|
|
|
|
|
|
308
|
18
|
100
|
|
|
|
64
|
die __PACKAGE__."::generate_to_end(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
|
309
|
|
|
|
|
|
|
|
310
|
17
|
|
|
|
|
57
|
my %opts = map lc, @_; # lowercase name,value pairs for canonical
|
311
|
17
|
100
|
|
|
|
43
|
my $limit = exists $opts{limit} ? $opts{limit} : 65535;
|
312
|
17
|
100
|
|
|
|
43
|
$limit = (2 ** $self->{taps}[0] - 1) if lc($limit) eq 'max';
|
313
|
|
|
|
|
|
|
# originally, the next block was "$self->rewind() if ($self->{i} && $opts{rewind});", but Devel::Cover complained that not all conditions were tested
|
314
|
|
|
|
|
|
|
# so I broke it into the following, which made Devel::Cover happy: note, it doesn't matter whether the i comes before or after rewind
|
315
|
17
|
100
|
|
|
|
35
|
if ($self->{i}) {
|
316
|
7
|
100
|
|
|
|
18
|
if( $opts{rewind} ) {
|
317
|
2
|
|
|
|
|
6
|
$self->rewind();
|
318
|
|
|
|
|
|
|
}
|
319
|
|
|
|
|
|
|
}
|
320
|
17
|
100
|
100
|
|
|
68
|
$self->{i} %= $self->{period} if defined $self->{period} && $self->{i} > $self->{period};
|
321
|
17
|
|
|
|
|
14
|
my $ret = '';
|
322
|
17
|
|
|
|
|
36
|
while( $self->{i} < $limit ) {
|
323
|
278986
|
|
|
|
|
266842
|
$ret .= scalar $self->next(); # need to force the scalar version to not push (i,value)
|
324
|
278986
|
100
|
100
|
|
|
711454
|
$limit = $self->{period} if defined $self->{period} && $self->{period} < $limit; # pick PERIOD if PERIOD smaller than LIMIT
|
325
|
|
|
|
|
|
|
}
|
326
|
17
|
100
|
|
|
|
325
|
return wantarray ? split(//, $ret) : $ret;
|
327
|
|
|
|
|
|
|
}
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
sub generate_all {
|
330
|
7
|
|
|
7
|
1
|
22
|
my $self = shift;
|
331
|
|
|
|
|
|
|
|
332
|
7
|
100
|
|
|
|
30
|
die __PACKAGE__."::generate_all(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
|
333
|
|
|
|
|
|
|
|
334
|
6
|
|
|
|
|
37
|
my %opts = @_;
|
335
|
6
|
|
|
|
|
17
|
$opts{rewind} = 1; # override existing rewind value
|
336
|
6
|
|
|
|
|
19
|
return generate_to_end($self, %opts);
|
337
|
|
|
|
|
|
|
}
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=back
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=head2 Information
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=over
|
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=item C<$i = $seq-Edescription>
|
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
Returns a string describing the sequence in terms of the polynomial.
|
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
$prbs7->description # "PRBS from polynomial x**7 + x**6 + 1"
|
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=cut
|
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub description {
|
354
|
10
|
|
|
10
|
1
|
746
|
my $self = shift;
|
355
|
10
|
|
|
|
|
15
|
my $p = '';
|
356
|
10
|
|
|
|
|
8
|
foreach ( reverse sort {$a <=> $b} @{ $self->{taps} } ) {
|
|
11
|
|
|
|
|
25
|
|
|
10
|
|
|
|
|
35
|
|
357
|
21
|
100
|
|
|
|
42
|
$p .= ' + ' if $p;
|
358
|
21
|
|
|
|
|
36
|
$p .= "x**$_";
|
359
|
|
|
|
|
|
|
}
|
360
|
10
|
|
|
|
|
49
|
return "PRBS from polynomial $p + 1";
|
361
|
|
|
|
|
|
|
}
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
=item C<$i = $seq-Etaps>
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
Returns an array-reference containing the list of tap identifiers, which could then be passed to C<-Enew(taps =E ...)>.
|
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
my $old_prbs = ...;
|
368
|
|
|
|
|
|
|
my $new_prbs = Math::PRBS->new( taps => $old_prbs->taps() );
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=cut
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub taps {
|
373
|
11
|
|
|
11
|
1
|
22
|
my @taps = @{ $_[0]->{taps} };
|
|
11
|
|
|
|
|
32
|
|
374
|
11
|
|
|
|
|
64
|
return [@taps];
|
375
|
|
|
|
|
|
|
}
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=item C<$i = $seq-Eperiod( I 'estimate' | $n | 'max'> )>
|
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Returns the period of the sequence.
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
Without any arguments, will return undef if the period hasn't been determined yet (ie, haven't travelled far enough in the sequence):
|
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
$i = $seq->period(); # unknown => undef
|
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
If I is set to 'estimate', will return C if the period hasn't been determined yet:
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
$i = $seq->period(force => 'estimate'); # unknown => 2**k - 1
|
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
If I is set to an integer C<$n>, it will try to generate the whole sequence (up to C= $n>), and return the period if found, or undef if not found.
|
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
$i = $seq->period(force => $n); # look until $n; undef if sequence period still not found
|
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
If I is set 'max', it will loop thru the entire sequence (up to C), and return the period that was found. It will still return undef if still not found, but all sequences B find the period within C<2**k-1>. If you find a sequence that doesn't, feel free to file a bug report, including the Cnew()> command listing the taps array or poly string; if C is greater than C<32>, please include a code that fixes the bug in the bug report, as development resources may not allow for debug of issues when C 32>.
|
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
$i = $seq->period(force => 'max'); # look until 2**k - 1; undef if sequence period still not found
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=cut
|
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
sub period {
|
401
|
17
|
|
|
17
|
1
|
1089
|
my $self = shift;
|
402
|
17
|
100
|
|
|
|
70
|
return $self->{period} if defined $self->{period}; # if period's already computed, use it
|
403
|
|
|
|
|
|
|
|
404
|
7
|
100
|
|
|
|
29
|
die __PACKAGE__."::period(@_) requires even number of arguments, expecting name=>value pairs" unless 0 == @_ % 2;
|
405
|
|
|
|
|
|
|
|
406
|
6
|
|
|
|
|
26
|
my %opts = map lc, @_; # lowercase the arguments and make them into a canonical hash
|
407
|
6
|
100
|
|
|
|
16
|
my $force = exists($opts{force}) ? $opts{force} : 'not';
|
408
|
6
|
100
|
|
|
|
43
|
return $self->{period} if 'not' eq $force; # if not forced, return the undefined period
|
409
|
|
|
|
|
|
|
|
410
|
4
|
|
|
|
|
10
|
my $max = 2**$self->{taps}[0] - 1; # if forced, max is 2**k-1
|
411
|
4
|
100
|
|
|
|
12
|
return $max if $force eq 'estimate'; # if estimate, guess that period is maximal
|
412
|
|
|
|
|
|
|
|
413
|
3
|
100
|
|
|
|
11
|
$max = $force unless $force =~ /[^\d]/; # don't change max if force is a string (or negative, or floatingpoint)
|
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# ... loop thru all, until limit is reached or period is defined
|
416
|
3
|
|
100
|
|
|
21
|
$self->next while $self->{i}<$max && !defined $self->{period};
|
417
|
|
|
|
|
|
|
|
418
|
3
|
|
|
|
|
31
|
return $self->{period};
|
419
|
|
|
|
|
|
|
}
|
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
=item C<$i = $seq-Eoeis_anum>
|
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
For known polynomials, return the L "A" number. For example, you can go to L to look at the sequence A011686.
|
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Not all maximum-length PRBS sequences (binary m-sequences) are in OEIS. Of the four "standard" PRBS (7, 15, 23, 31) mentioned above, only PRBS7 is there, as L. If you have the A-number for other m-sequences that aren't included below, please let the module maintainer know.
|
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Polynomial | Taps | OEIS
|
428
|
|
|
|
|
|
|
----------------------------------------------+-----------------------+---------
|
429
|
|
|
|
|
|
|
x**2 + x**1 + 1 | [ 2, 1 ] | A011655
|
430
|
|
|
|
|
|
|
x**3 + x**2 + 1 | [ 3, 2 ] | A011656
|
431
|
|
|
|
|
|
|
x**3 + x**1 + 1 | [ 3, 1 ] | A011657
|
432
|
|
|
|
|
|
|
x**4 + x**3 + x**2 + x**1 + 1 | [ 4, 3, 2, 1 ] | A011658
|
433
|
|
|
|
|
|
|
x**4 + x**1 + 1 | [ 4, 1 ] | A011659
|
434
|
|
|
|
|
|
|
x**5 + x**4 + x**2 + x**1 + 1 | [ 5, 4, 2, 1 ] | A011660
|
435
|
|
|
|
|
|
|
x**5 + x**3 + x**2 + x**1 + 1 | [ 5, 3, 2, 1 ] | A011661
|
436
|
|
|
|
|
|
|
x**5 + x**2 + 1 | [ 5, 2 ] | A011662
|
437
|
|
|
|
|
|
|
x**5 + x**4 + x**3 + x**1 + 1 | [ 5, 4, 3, 1 ] | A011663
|
438
|
|
|
|
|
|
|
x**5 + x**3 + 1 | [ 5, 3 ] | A011664
|
439
|
|
|
|
|
|
|
x**5 + x**4 + x**3 + x**2 + 1 | [ 5, 4, 3, 2 ] | A011665
|
440
|
|
|
|
|
|
|
x**6 + x**5 + x**4 + x**1 + 1 | [ 6, 5, 4, 1 ] | A011666
|
441
|
|
|
|
|
|
|
x**6 + x**5 + x**3 + x**2 + 1 | [ 6, 5, 3, 2 ] | A011667
|
442
|
|
|
|
|
|
|
x**6 + x**5 + x**2 + x**1 + 1 | [ 6, 5, 2, 1 ] | A011668
|
443
|
|
|
|
|
|
|
x**6 + x**1 + 1 | [ 6, 1 ] | A011669
|
444
|
|
|
|
|
|
|
x**6 + x**4 + x**3 + x**1 + 1 | [ 6, 4, 3, 1 ] | A011670
|
445
|
|
|
|
|
|
|
x**6 + x**5 + x**4 + x**2 + 1 | [ 6, 5, 4, 2 ] | A011671
|
446
|
|
|
|
|
|
|
x**6 + x**3 + 1 | [ 6, 3 ] | A011672
|
447
|
|
|
|
|
|
|
x**6 + x**5 + 1 | [ 6, 5 ] | A011673
|
448
|
|
|
|
|
|
|
x**7 + x**6 + x**5 + x**4 + x**3 + x**2 + 1 | [ 7, 6, 5, 4, 3, 2 ] | A011674
|
449
|
|
|
|
|
|
|
x**7 + x**4 + 1 | [ 7, 4 ] | A011675
|
450
|
|
|
|
|
|
|
x**7 + x**6 + x**4 + x**2 + 1 | [ 7, 6, 4, 2 ] | A011676
|
451
|
|
|
|
|
|
|
x**7 + x**5 + x**2 + x**1 + 1 | [ 7, 5, 2, 1 ] | A011677
|
452
|
|
|
|
|
|
|
x**7 + x**5 + x**3 + x**1 + 1 | [ 7, 5, 3, 1 ] | A011678
|
453
|
|
|
|
|
|
|
x**7 + x**6 + x**4 + x**1 + 1 | [ 7, 6, 4, 1 ] | A011679
|
454
|
|
|
|
|
|
|
x**7 + x**6 + x**5 + x**4 + x**2 + x**1 + 1 | [ 7, 6, 5, 4, 2, 1 ] | A011680
|
455
|
|
|
|
|
|
|
x**7 + x**6 + x**5 + x**3 + x**2 + x**1 + 1 | [ 7, 6, 5, 3, 2, 1 ] | A011681
|
456
|
|
|
|
|
|
|
x**7 + x**1 + 1 | [ 7, 1 ] | A011682
|
457
|
|
|
|
|
|
|
x**7 + x**5 + x**4 + x**3 + x**2 + x**1 + 1 | [ 7, 5, 4, 3, 2, 1 ] | A011683
|
458
|
|
|
|
|
|
|
x**7 + x**4 + x**3 + x**2 + 1 | [ 7, 4, 3, 2 ] | A011684
|
459
|
|
|
|
|
|
|
x**7 + x**6 + x**3 + x**1 + 1 | [ 7, 6, 3, 1 ] | A011685
|
460
|
|
|
|
|
|
|
x**7 + x**6 + 1 | [ 7, 6 ] | A011686
|
461
|
|
|
|
|
|
|
x**7 + x**6 + x**5 + x**4 + 1 | [ 7, 6, 5, 4 ] | A011687
|
462
|
|
|
|
|
|
|
x**7 + x**5 + x**4 + x**3 + 1 | [ 7, 5, 4, 3 ] | A011688
|
463
|
|
|
|
|
|
|
x**7 + x**3 + x**2 + x**1 + 1 | [ 7, 3, 2, 1 ] | A011689
|
464
|
|
|
|
|
|
|
x**7 + x**3 + 1 | [ 7, 3 ] | A011690
|
465
|
|
|
|
|
|
|
x**7 + x**6 + x**5 + x**2 + 1 | [ 7, 6, 5, 2 ] | A011691
|
466
|
|
|
|
|
|
|
x**8 + x**6 + x**4 + x**3 + x**2 + x**1 + 1 | [ 8, 6, 4, 3, 2, 1 ] | A011692
|
467
|
|
|
|
|
|
|
x**8 + x**5 + x**4 + x**3 + 1 | [ 8, 5, 4, 3 ] | A011693
|
468
|
|
|
|
|
|
|
x**8 + x**7 + x**5 + x**3 + 1 | [ 8, 7, 5, 3 ] | A011694
|
469
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**5 + x**4 + x**2 + 1 | [ 8, 7, 6, 5, 4, 2 ] | A011695
|
470
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**5 + x**4 + x**3 + 1 | [ 8, 7, 6, 5, 4, 3 ] | A011696
|
471
|
|
|
|
|
|
|
x**8 + x**4 + x**3 + x**2 + 1 | [ 8, 4, 3, 2 ] | A011697
|
472
|
|
|
|
|
|
|
x**8 + x**6 + x**5 + x**4 + x**2 + x**1 + 1 | [ 8, 6, 5, 4, 2, 1 ] | A011698
|
473
|
|
|
|
|
|
|
x**8 + x**7 + x**5 + x**1 + 1 | [ 8, 7, 5, 1 ] | A011699
|
474
|
|
|
|
|
|
|
x**8 + x**7 + x**3 + x**1 + 1 | [ 8, 7, 3, 1 ] | A011700
|
475
|
|
|
|
|
|
|
x**8 + x**5 + x**4 + x**3 + x**2 + x**1 + 1 | [ 8, 5, 4, 3, 2, 1 ] | A011701
|
476
|
|
|
|
|
|
|
x**8 + x**7 + x**5 + x**4 + x**3 + x**2 + 1 | [ 8, 7, 5, 4, 3, 2 ] | A011702
|
477
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**4 + x**3 + x**2 + 1 | [ 8, 7, 6, 4, 3, 2 ] | A011703
|
478
|
|
|
|
|
|
|
x**8 + x**6 + x**3 + x**2 + 1 | [ 8, 6, 3, 2 ] | A011704
|
479
|
|
|
|
|
|
|
x**8 + x**7 + x**3 + x**2 + 1 | [ 8, 7, 3, 2 ] | A011705
|
480
|
|
|
|
|
|
|
x**8 + x**6 + x**5 + x**2 + 1 | [ 8, 6, 5, 2 ] | A011706
|
481
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**4 + x**2 + x**1 + 1 | [ 8, 7, 6, 4, 2, 1 ] | A011707
|
482
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**3 + x**2 + x**1 + 1 | [ 8, 7, 6, 3, 2, 1 ] | A011708
|
483
|
|
|
|
|
|
|
x**8 + x**7 + x**2 + x**1 + 1 | [ 8, 7, 2, 1 ] | A011709
|
484
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**1 + 1 | [ 8, 7, 6, 1 ] | A011710
|
485
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**5 + x**2 + x**1 + 1 | [ 8, 7, 6, 5, 2, 1 ] | A011711
|
486
|
|
|
|
|
|
|
x**8 + x**7 + x**5 + x**4 + 1 | [ 8, 7, 5, 4 ] | A011712
|
487
|
|
|
|
|
|
|
x**8 + x**6 + x**5 + x**1 + 1 | [ 8, 6, 5, 1 ] | A011713
|
488
|
|
|
|
|
|
|
x**8 + x**4 + x**3 + x**1 + 1 | [ 8, 4, 3, 1 ] | A011714
|
489
|
|
|
|
|
|
|
x**8 + x**6 + x**5 + x**4 + 1 | [ 8, 6, 5, 4 ] | A011715
|
490
|
|
|
|
|
|
|
x**8 + x**7 + x**6 + x**5 + x**4 + x**1 + 1 | [ 8, 7, 6, 5, 4, 1 ] | A011716
|
491
|
|
|
|
|
|
|
x**8 + x**5 + x**3 + x**2 + 1 | [ 8, 5, 3, 2 ] | A011717
|
492
|
|
|
|
|
|
|
x**8 + x**6 + x**5 + x**4 + x**3 + x**1 + 1 | [ 8, 6, 5, 4, 3, 1 ] | A011718
|
493
|
|
|
|
|
|
|
x**8 + x**5 + x**3 + x**1 + 1 | [ 8, 5, 3, 1 ] | A011719
|
494
|
|
|
|
|
|
|
x**8 + x**7 + x**4 + x**3 + x**2 + x**1 + 1 | [ 8, 7, 4, 3, 2, 1 ] | A011720
|
495
|
|
|
|
|
|
|
x**8 + x**6 + x**5 + x**3 + 1 | [ 8, 6, 5, 3 ] | A011721
|
496
|
|
|
|
|
|
|
x**9 + x**4 + 1 | [ 9, 4 ] | A011722
|
497
|
|
|
|
|
|
|
x**10 + x**3 + 1 | [ 10, 3 ] | A011723
|
498
|
|
|
|
|
|
|
x**11 + x**2 + 1 | [ 11, 2 ] | A011724
|
499
|
|
|
|
|
|
|
x**12 + x**7 + x**4 + x**3 + 1 | [ 12, 7, 4, 3 ] | A011725
|
500
|
|
|
|
|
|
|
x**13 + x**4 + x**3 + x**1 + 1 | [ 13, 4, 3, 1 ] | A011726
|
501
|
|
|
|
|
|
|
x**14 + x**12 + x**11 + x**1 + 1 | [ 14, 12, 11, 1 ] | A011727
|
502
|
|
|
|
|
|
|
x**15 + x**1 + 1 | [ 15, 1 ] | A011728
|
503
|
|
|
|
|
|
|
x**16 + x**5 + x**3 + x**2 + 1 | [ 16, 5, 3, 2 ] | A011729
|
504
|
|
|
|
|
|
|
x**17 + x**3 + 1 | [ 17, 3 ] | A011730
|
505
|
|
|
|
|
|
|
x**18 + x**7 + 1 | [ 18, 7 ] | A011731
|
506
|
|
|
|
|
|
|
x**19 + x**6 + x**5 + x**1 + 1 | [ 19, 6, 5, 1 ] | A011732
|
507
|
|
|
|
|
|
|
x**20 + x**3 + 1 | [ 20, 3 ] | A011733
|
508
|
|
|
|
|
|
|
x**21 + x**2 + 1 | [ 21, 2 ] | A011734
|
509
|
|
|
|
|
|
|
x**22 + x**1 + 1 | [ 22, 1 ] | A011735
|
510
|
|
|
|
|
|
|
x**23 + x**5 + 1 | [ 23, 5 ] | A011736
|
511
|
|
|
|
|
|
|
x**24 + x**4 + x**3 + x**1 + 1 | [ 24, 4, 3, 1 ] | A011737
|
512
|
|
|
|
|
|
|
x**25 + x**3 + 1 | [ 25, 3 ] | A011738
|
513
|
|
|
|
|
|
|
x**26 + x**8 + x**7 + x**1 + 1 | [ 26, 8, 7, 1 ] | A011739
|
514
|
|
|
|
|
|
|
x**27 + x**8 + x**7 + x**1 + 1 | [ 27, 8, 7, 1 ] | A011740
|
515
|
|
|
|
|
|
|
x**28 + x**3 + 1 | [ 28, 3 ] | A011741
|
516
|
|
|
|
|
|
|
x**29 + x**2 + 1 | [ 29, 2 ] | A011742
|
517
|
|
|
|
|
|
|
x**30 + x**16 + x**15 + x**1 + 1 | [ 30, 16, 15, 1 ] | A011743
|
518
|
|
|
|
|
|
|
x**31 + x**3 + 1 | [ 31, 3 ] | A011744
|
519
|
|
|
|
|
|
|
x**32 + x**28 + x**27 + x**1 + 1 | [ 32, 28, 27, 1 ] | A011745
|
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=cut
|
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
my %OEIS = (
|
524
|
|
|
|
|
|
|
join(';', @{ [ 2, 1 ] } ) => 'A011655',
|
525
|
|
|
|
|
|
|
join(';', @{ [ 3, 2 ] } ) => 'A011656',
|
526
|
|
|
|
|
|
|
join(';', @{ [ 3, 1 ] } ) => 'A011657',
|
527
|
|
|
|
|
|
|
join(';', @{ [ 4, 3, 2, 1 ] } ) => 'A011658',
|
528
|
|
|
|
|
|
|
join(';', @{ [ 4, 1 ] } ) => 'A011659',
|
529
|
|
|
|
|
|
|
join(';', @{ [ 5, 4, 2, 1 ] } ) => 'A011660',
|
530
|
|
|
|
|
|
|
join(';', @{ [ 5, 3, 2, 1 ] } ) => 'A011661',
|
531
|
|
|
|
|
|
|
join(';', @{ [ 5, 2 ] } ) => 'A011662',
|
532
|
|
|
|
|
|
|
join(';', @{ [ 5, 4, 3, 1 ] } ) => 'A011663',
|
533
|
|
|
|
|
|
|
join(';', @{ [ 5, 3 ] } ) => 'A011664',
|
534
|
|
|
|
|
|
|
join(';', @{ [ 5, 4, 3, 2 ] } ) => 'A011665',
|
535
|
|
|
|
|
|
|
join(';', @{ [ 6, 5, 4, 1 ] } ) => 'A011666',
|
536
|
|
|
|
|
|
|
join(';', @{ [ 6, 5, 3, 2 ] } ) => 'A011667',
|
537
|
|
|
|
|
|
|
join(';', @{ [ 6, 5, 2, 1 ] } ) => 'A011668',
|
538
|
|
|
|
|
|
|
join(';', @{ [ 6, 1 ] } ) => 'A011669',
|
539
|
|
|
|
|
|
|
join(';', @{ [ 6, 4, 3, 1 ] } ) => 'A011670',
|
540
|
|
|
|
|
|
|
join(';', @{ [ 6, 5, 4, 2 ] } ) => 'A011671',
|
541
|
|
|
|
|
|
|
join(';', @{ [ 6, 3 ] } ) => 'A011672',
|
542
|
|
|
|
|
|
|
join(';', @{ [ 6, 5 ] } ) => 'A011673',
|
543
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 5, 4, 3, 2 ] } ) => 'A011674',
|
544
|
|
|
|
|
|
|
join(';', @{ [ 7, 4 ] } ) => 'A011675',
|
545
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 4, 2 ] } ) => 'A011676',
|
546
|
|
|
|
|
|
|
join(';', @{ [ 7, 5, 2, 1 ] } ) => 'A011677',
|
547
|
|
|
|
|
|
|
join(';', @{ [ 7, 5, 3, 1 ] } ) => 'A011678',
|
548
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 4, 1 ] } ) => 'A011679',
|
549
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 5, 4, 2, 1 ] } ) => 'A011680',
|
550
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 5, 3, 2, 1 ] } ) => 'A011681',
|
551
|
|
|
|
|
|
|
join(';', @{ [ 7, 1 ] } ) => 'A011682',
|
552
|
|
|
|
|
|
|
join(';', @{ [ 7, 5, 4, 3, 2, 1 ] } ) => 'A011683',
|
553
|
|
|
|
|
|
|
join(';', @{ [ 7, 4, 3, 2 ] } ) => 'A011684',
|
554
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 3, 1 ] } ) => 'A011685',
|
555
|
|
|
|
|
|
|
join(';', @{ [ 7, 6 ] } ) => 'A011686',
|
556
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 5, 4 ] } ) => 'A011687',
|
557
|
|
|
|
|
|
|
join(';', @{ [ 7, 5, 4, 3 ] } ) => 'A011688',
|
558
|
|
|
|
|
|
|
join(';', @{ [ 7, 3, 2, 1 ] } ) => 'A011689',
|
559
|
|
|
|
|
|
|
join(';', @{ [ 7, 3 ] } ) => 'A011690',
|
560
|
|
|
|
|
|
|
join(';', @{ [ 7, 6, 5, 2 ] } ) => 'A011691',
|
561
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 4, 3, 2, 1 ] } ) => 'A011692',
|
562
|
|
|
|
|
|
|
join(';', @{ [ 8, 5, 4, 3 ] } ) => 'A011693',
|
563
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 5, 3 ] } ) => 'A011694',
|
564
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 5, 4, 2 ] } ) => 'A011695',
|
565
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 5, 4, 3 ] } ) => 'A011696',
|
566
|
|
|
|
|
|
|
join(';', @{ [ 8, 4, 3, 2 ] } ) => 'A011697',
|
567
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 5, 4, 2, 1 ] } ) => 'A011698',
|
568
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 5, 1 ] } ) => 'A011699',
|
569
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 3, 1 ] } ) => 'A011700',
|
570
|
|
|
|
|
|
|
join(';', @{ [ 8, 5, 4, 3, 2, 1 ] } ) => 'A011701',
|
571
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 5, 4, 3, 2 ] } ) => 'A011702',
|
572
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 4, 3, 2 ] } ) => 'A011703',
|
573
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 3, 2 ] } ) => 'A011704',
|
574
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 3, 2 ] } ) => 'A011705',
|
575
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 5, 2 ] } ) => 'A011706',
|
576
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 4, 2, 1 ] } ) => 'A011707',
|
577
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 3, 2, 1 ] } ) => 'A011708',
|
578
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 2, 1 ] } ) => 'A011709',
|
579
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 1 ] } ) => 'A011710',
|
580
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 5, 2, 1 ] } ) => 'A011711',
|
581
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 5, 4 ] } ) => 'A011712',
|
582
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 5, 1 ] } ) => 'A011713',
|
583
|
|
|
|
|
|
|
join(';', @{ [ 8, 4, 3, 1 ] } ) => 'A011714',
|
584
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 5, 4 ] } ) => 'A011715',
|
585
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 6, 5, 4, 1 ] } ) => 'A011716',
|
586
|
|
|
|
|
|
|
join(';', @{ [ 8, 5, 3, 2 ] } ) => 'A011717',
|
587
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 5, 4, 3, 1 ] } ) => 'A011718',
|
588
|
|
|
|
|
|
|
join(';', @{ [ 8, 5, 3, 1 ] } ) => 'A011719',
|
589
|
|
|
|
|
|
|
join(';', @{ [ 8, 7, 4, 3, 2, 1 ] } ) => 'A011720',
|
590
|
|
|
|
|
|
|
join(';', @{ [ 8, 6, 5, 3 ] } ) => 'A011721',
|
591
|
|
|
|
|
|
|
join(';', @{ [ 9, 4 ] } ) => 'A011722',
|
592
|
|
|
|
|
|
|
join(';', @{ [ 10, 3 ] } ) => 'A011723',
|
593
|
|
|
|
|
|
|
join(';', @{ [ 11, 2 ] } ) => 'A011724',
|
594
|
|
|
|
|
|
|
join(';', @{ [ 12, 7, 4, 3 ] } ) => 'A011725',
|
595
|
|
|
|
|
|
|
join(';', @{ [ 13, 4, 3, 1 ] } ) => 'A011726',
|
596
|
|
|
|
|
|
|
join(';', @{ [ 14, 12, 11, 1 ] } ) => 'A011727',
|
597
|
|
|
|
|
|
|
join(';', @{ [ 15, 1 ] } ) => 'A011728',
|
598
|
|
|
|
|
|
|
join(';', @{ [ 16, 5, 3, 2 ] } ) => 'A011729',
|
599
|
|
|
|
|
|
|
join(';', @{ [ 17, 3 ] } ) => 'A011730',
|
600
|
|
|
|
|
|
|
join(';', @{ [ 18, 7 ] } ) => 'A011731',
|
601
|
|
|
|
|
|
|
join(';', @{ [ 19, 6, 5, 1 ] } ) => 'A011732',
|
602
|
|
|
|
|
|
|
join(';', @{ [ 20, 3 ] } ) => 'A011733',
|
603
|
|
|
|
|
|
|
join(';', @{ [ 21, 2 ] } ) => 'A011734',
|
604
|
|
|
|
|
|
|
join(';', @{ [ 22, 1 ] } ) => 'A011735',
|
605
|
|
|
|
|
|
|
join(';', @{ [ 23, 5 ] } ) => 'A011736',
|
606
|
|
|
|
|
|
|
join(';', @{ [ 24, 4, 3, 1 ] } ) => 'A011737',
|
607
|
|
|
|
|
|
|
join(';', @{ [ 25, 3 ] } ) => 'A011738',
|
608
|
|
|
|
|
|
|
join(';', @{ [ 26, 8, 7, 1 ] } ) => 'A011739',
|
609
|
|
|
|
|
|
|
join(';', @{ [ 27, 8, 7, 1 ] } ) => 'A011740',
|
610
|
|
|
|
|
|
|
join(';', @{ [ 28, 3 ] } ) => 'A011741',
|
611
|
|
|
|
|
|
|
join(';', @{ [ 29, 2 ] } ) => 'A011742',
|
612
|
|
|
|
|
|
|
join(';', @{ [ 30, 16, 15, 1 ] } ) => 'A011743',
|
613
|
|
|
|
|
|
|
join(';', @{ [ 31, 3 ] } ) => 'A011744',
|
614
|
|
|
|
|
|
|
join(';', @{ [ 32, 28, 27, 1 ] } ) => 'A011745',
|
615
|
|
|
|
|
|
|
);
|
616
|
|
|
|
|
|
|
sub oeis_anum {
|
617
|
7
|
|
|
7
|
1
|
12
|
my $taps = join ';', @{ $_[0]->{taps} };
|
|
7
|
|
|
|
|
19
|
|
618
|
7
|
100
|
|
|
|
43
|
return exists $OEIS{$taps} ? $OEIS{$taps} : undef;
|
619
|
|
|
|
|
|
|
}
|
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
=back
|
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head1 THEORY
|
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
A pseudorandom binary sequence (PRBS) is the sequence of N unique bits, in this case generated from an LFSR. Once it generates the N bits, it loops around and repeats that seqence. While still within the unique N bits, the sequence of N bits shares some properties with a truly random sequence of the same length. The benefit of this sequence is that, while it shares statistical properites with a random sequence, it is actually deterministic, so is often used to deterministically test hardware or software that requires a data stream that needs pseudorandom properties.
|
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
In an LFSR, the polynomial description (like C) indicates which bits are "tapped" to create the feedback bit: the taps are the powers of x in the polynomial (3 and 2). The C<1> is really the C term, and isn't a "tap", in the sense that it isn't used for generating the feedback; instead, that is the location where the new feedback bit comes back into the shift register; the C<1> is in all characteristic polynomials, and is implied when creating a new instance of B.
|
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
If the largest power of the polynomial is C, there are C bits in the register (one for each of the powers C and one for the C's feedback bit). For any given C, the largest sequence that can be produced is C, and that sequence is called a maximum length sequence or m-sequence; there can be more than one m-sequence for a given C. One useful feature of an m-sequence is that if you divide it into every possible partial sequence that's C bits long (wraping from N-1 to 0 to make the last few partial sequences also C bits), you will generate every possible combination of C bits (*), except for C zeroes in a row. For example,
|
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# x**3 + x**2 + 1 = "1011100"
|
633
|
|
|
|
|
|
|
"_101_1100 " -> 101
|
634
|
|
|
|
|
|
|
"1_011_100 " -> 011
|
635
|
|
|
|
|
|
|
"10_111_00 " -> 111
|
636
|
|
|
|
|
|
|
"101_110_0 " -> 110
|
637
|
|
|
|
|
|
|
"1011_100_ " -> 100
|
638
|
|
|
|
|
|
|
"1_0111_00 " -> 001 (requires wrap to get three digits: 00 from the end, and 1 from the beginning)
|
639
|
|
|
|
|
|
|
"10_1110_0 " -> 010 (requires wrap to get three digits: 0 from the end, and 10 from the beginning)
|
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
The Wikipedia:LFSR article (see L) lists some polynomials that create m-sequence for various register sizes, and links to Philip Koopman's complete list up to C.
|
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
If you want to create try own polynonial to find a long m-sequence, here are some things to consider: 1) the number of taps for the feedback (remembering not to count the feedback bit as a tap) must be even; 2) the entire set of taps must be relatively prime; 3) those two conditions are necesssary, but not sufficient, so you may have to try multiple polynomials to find an m-sequence; 4) keep in mind that the time to compute the period (and thus determine if it's an m-sequence) doubles every time C increases by 1; as the time increases, it makes more sense to look at the complete list up to C), and pure-perl is probably tpp wrong language for searching C64>.
|
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
(*) Since a maximum length sequence contains every k-bit combination (except all zeroes), it can be used for verifying that software or hardware behaves properly for every possible sequence of k-bits.
|
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
=head1 REFERENCES
|
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=over
|
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=item * Wikipedia:Linear-feedback Shift Register (LFSR) at L
|
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=over
|
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
=item * Article includes a list of some L
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
=item * Article links to Philip Koopman's complete list of maximum length polynomials, up to C at L
|
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
=back
|
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
=item * Wikipedia:Pseudorandom Binary Sequence (PRBS) at L
|
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=over
|
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
=item * The underlying algorithm in B is based on the C code in this article's L<"Practical Implementation"|https://en.wikipedia.org/w/index.php?title=Pseudorandom_binary_sequence&oldid=700999060#Practical_implementation>
|
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=back
|
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=item * Wikipedia:Maximum Length Sequence (m-sequence) at L
|
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
=over
|
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
=item * Article describes some of the properties of m-sequences
|
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
=back
|
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
=back
|
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=head1 AUTHOR
|
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
Peter C. Jones Cpetercj AT cpan DOT orgE>
|
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
Please report any bugs or feature requests thru the web interface at
|
684
|
|
|
|
|
|
|
L
|
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=head1 COPYRIGHT
|
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
Copyright (C) 2016 Peter C. Jones
|
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=head1 LICENCE
|
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
693
|
|
|
|
|
|
|
under the terms of either: the GNU General Public License as published
|
694
|
|
|
|
|
|
|
by the Free Software Foundation; or the Artistic License.
|
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
See L for more information.
|
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=cut
|
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
1; |