001/* Scramble an input bit sequence in a pseudo random way. 002 003 Copyright (c) 2003-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.actor.lib.comm; 029 030import ptolemy.actor.lib.Transformer; 031import ptolemy.data.BooleanToken; 032import ptolemy.data.IntToken; 033import ptolemy.data.expr.Parameter; 034import ptolemy.data.type.BaseType; 035import ptolemy.kernel.CompositeEntity; 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.NameDuplicationException; 039 040/////////////////////////////////////////////////////////////////// 041//// Scrambler 042 043/** 044 Scramble the input bit sequence using a feedback shift register. 045 The initial state of the shift register is given by the <i>initialState</i> 046 parameter, which should be a non-negative integer. 047 The taps of the feedback shift register are given by the <i>polynomial</i> 048 parameter, which should be a positive integer. 049 The n-th bit of this integer indicates whether the n-th tap of the delay 050 line is fed back. 051 The low-order bit is called the 0-th bit, and should always be set. 052 The next low-order bit indicates whether the output of the first delay 053 should be fed back, etc. 054 The input port receives boolean tokens. "TRUE" is treated as 1 and "FALSE" 055 is treated as 0. All the bits that are fed back are exclusive-ored together 056 (i.e., their parity is computed), and the result is exclusive-ored with the 057 input bit. The result is produced at the output and shifted into the delay line. 058 <p> 059 With a proper choice of polynomial, the resulting output appears highly 060 random even if the input is highly non-random. 061 If the polynomial is a <i>primitive polynomial</i>, then the feedback 062 shift register is a so-called <i>maximal length feedback shift register</i>. 063 This means that with a constant input (or no input, which is equivalent 064 to a constant <i>false</i> input) the output will be a sequence with 065 period 2<sup><i>N</i></sup>-1, where <i>N</i> is the order of the 066 polynomial (the length of the shift register). 067 This is the longest possible sequence. 068 Moreover, within this period, the sequence will appear to be white, 069 in that a computed autocorrelation will be very nearly an impulse. 070 Thus, the scrambler with a constant input can be very effectively used 071 to generate a pseudo-random bit sequence. 072 <p> 073 The maximal-length feedback shift register with constant input will 074 pass through 2<sup><i>N</i></sup>-1 states before returning to a state 075 it has been in before. This is one short of the 2<sup><i>N</i></sup> 076 states that a register with <i>N</i> bits can take on. This one missing 077 state, in fact, is a <i>lock-up</i> state, in that if the input is 078 an appropriate constant, the scrambler will cease to produce random-looking 079 output, and will output a constant. For example, if the input is all zeros, 080 and the initial state of the scrambler is zero, then the outputs will be all 081 zero, hardly random. This is easily avoided by initializing the scrambler 082 to some non-zero state. The default value for the <i>shiftReg</i> is set to 1. 083 <p> 084 The <i>polynomial</i> must be carefully chosen. It must represent a 085 <i>primitive polynomial</i>, which is one that cannot be factored into two 086 (nontrivial) polynomials with binary coefficients. See Lee and Messerschmitt 087 (Kluwer, 1994) for more details. For convenience, we give here 088 a set of primitive polynomials 089 (expressed as octal numbers so that they are easily translated into taps 090 on shift register). All of these will result in maximal-length pseudo-random 091 sequences if the input is constant and lock-up is avoided: 092 <pre> 093 order polynomial 094 2 07 095 3 013 096 4 023 097 5 045 098 6 0103 099 7 0211 100 8 0435 101 9 01021 102 10 02011 103 11 04005 104 12 010123 105 13 020033 106 14 042103 107 15 0100003 108 16 0210013 109 17 0400011 110 18 01000201 111 19 02000047 112 20 04000011 113 21 010000005 114 22 020000003 115 23 040000041 116 24 0100000207 117 25 0200000011 118 26 0400000107 119 27 01000000047 120 28 02000000011 121 29 04000000005 122 30 010040000007 123 </pre> 124 <p> 125 The leading zero in the polynomial indicates an octal number. 126 Note also that reversing the order of the bits in any of these numbers 127 will also result in a primitive polynomial. 128 Thus, the default value for the polynomial parameter 129 is 0440001 in octal, or "100 100 000 000 000 001" in binary. 130 Reversing these bits we get "100 000 000 000 001 001" in binary, or 131 0400011 in octal. 132 This latter number is the one listed above as the primitive polynomial 133 of order 17. 134 The order is simply the index of the highest-order non-zero in the polynomial, 135 where the low-order bit has index zero. 136 <p> 137 Since the polynomial and the feedback shift register are both implemented 138 using type "int", the order of the polynomial is limited by the size of 139 the "int" data type. 140 For simplicity and portability, the polynomial is not allowed to be 141 interpreted as a negative integer, so the sign bit cannot be used. 142 Thus, if "int" is a 32-bit word, then the highest order polynomial allowed 143 is 30 (recall that indexing for the order starts at zero, and we cannot 144 use the sign bit). 145 Java has 32-bit integers, so we give the primitive 146 polynomials above only up to order 30. 147 <p> 148 For more information on scrambler, see Lee and Messerschmitt, Digital 149 Communication, Second Edition, Kluwer Academic Publishers, 1994, pp. 595-603. 150 <p> 151 @author Edward A. Lee and Ye Zhou 152 @version $Id$ 153 @since Ptolemy II 3.0 154 @Pt.ProposedRating Red (eal) 155 @Pt.AcceptedRating Red (cxh) 156 */ 157public class Scrambler extends Transformer { 158 /** Construct an actor with the given container and name. 159 * The output and trigger ports are also constructed. 160 * @param container The container. 161 * @param name The name of this actor. 162 * @exception IllegalActionException If the entity cannot be contained 163 * by the proposed container. 164 * @exception NameDuplicationException If the container already has an 165 * actor with this name. 166 */ 167 public Scrambler(CompositeEntity container, String name) 168 throws NameDuplicationException, IllegalActionException { 169 super(container, name); 170 171 polynomial = new Parameter(this, "polynomial"); 172 polynomial.setTypeEquals(BaseType.INT); 173 polynomial.setExpression("0440001"); 174 175 initialState = new Parameter(this, "initialState"); 176 initialState.setTypeEquals(BaseType.INT); 177 initialState.setExpression("1"); 178 179 // Create input port and declare data types. 180 //input = new TypedIOPort(this, "input", true, false); 181 input.setTypeEquals(BaseType.BOOLEAN); 182 output.setTypeEquals(BaseType.BOOLEAN); 183 } 184 185 /////////////////////////////////////////////////////////////////// 186 //// ports and parameters //// 187 188 /** Integer defining a polynomial with binary coefficients. 189 * The coefficients indicate the presence (1) or absence (0) 190 * of a tap in a feedback shift register. This parameter should 191 * contain a positive integer with the lower-order bit being 1. 192 * Its default value is the integer 0440001. 193 */ 194 public Parameter polynomial; 195 196 /** Integer defining the initial state of the shift register. 197 * The n-th bit of the integer indicates the value of the 198 * n-th register. This parameter should be a non-negative 199 * integer. Its default value is the integer 1. 200 */ 201 public Parameter initialState; 202 203 /////////////////////////////////////////////////////////////////// 204 //// public methods //// 205 206 /** If the attribute being changed is <i>polynomial</i>, then 207 * verify that is a positive integer and the lower-order bit is 1. 208 * @param attribute The attribute that changed. 209 * @exception IllegalActionException If <i>polynomial</i> is 210 * non-positive or the lower-order bit is not 1. 211 */ 212 @Override 213 public void attributeChanged(Attribute attribute) 214 throws IllegalActionException { 215 if (attribute == polynomial) { 216 int mask = ((IntToken) polynomial.getToken()).intValue(); 217 218 if (mask <= 0) { 219 throw new IllegalActionException(this, 220 "Polynomial is required to be strictly positive."); 221 } 222 223 if ((mask & 1) == 0) { 224 throw new IllegalActionException(this, 225 "The low-order bit of the the polynomial is not set."); 226 } 227 } else { 228 super.attributeChanged(attribute); 229 } 230 } 231 232 /** Read a bit from the input port and shift it into the shift register 233 * to scramble. Compute the parity and send <i>true</i> to the output 234 * port if it is 1; otherwise send <i>false</i> to the output port. 235 * The parity is shifted into the delay line for the next iteration. 236 */ 237 @Override 238 public void fire() throws IllegalActionException { 239 super.fire(); 240 _latestShiftReg = _shiftReg; 241 242 int mask = ((IntToken) polynomial.getToken()).intValue(); 243 int reg = _latestShiftReg << 1; 244 int masked = mask & reg; 245 246 // Find the parity of the "masked". 247 int parity = 0; 248 249 // Calculate the parity of the masked word. 250 while (masked > 0) { 251 parity = parity ^ masked & 1; 252 masked = masked >> 1; 253 } 254 255 // Exclusive-or with the input if there is any. 256 for (int i = 0; i < input.getWidth(); i++) { 257 if (input.hasToken(0)) { 258 BooleanToken inputToken = (BooleanToken) input.get(0); 259 boolean inputTokenValue = inputToken.booleanValue(); 260 parity = parity ^ (inputTokenValue ? 1 : 0); 261 } 262 } 263 264 _latestShiftReg = reg | parity; 265 266 if (parity == 1) { 267 output.broadcast(BooleanToken.TRUE); 268 } else { 269 output.broadcast(BooleanToken.FALSE); 270 } 271 } 272 273 /** Initialize the actor by resetting the shift register state 274 * equal to the value of <i>initialState</i>. 275 * @exception IllegalActionException If the parent class throws it. 276 */ 277 @Override 278 public void initialize() throws IllegalActionException { 279 super.initialize(); 280 _latestShiftReg = _shiftReg = ((IntToken) initialState.getToken()) 281 .intValue(); 282 } 283 284 /** Record the most recent shift register state as the new 285 * initial state for the next iteration. 286 * @exception IllegalActionException If the base class throws it 287 */ 288 @Override 289 public boolean postfire() throws IllegalActionException { 290 _shiftReg = _latestShiftReg; 291 return super.postfire(); 292 } 293 294 /////////////////////////////////////////////////////////////////// 295 //// private variables //// 296 // Record the state of the shift register. 297 private int _shiftReg; 298 299 // Updated state of the shift register. 300 private int _latestShiftReg; 301}