001/* Hamming Coder. 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.Token; 034import ptolemy.data.expr.Parameter; 035import ptolemy.data.type.BaseType; 036import ptolemy.kernel.CompositeEntity; 037import ptolemy.kernel.util.Attribute; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.Workspace; 041 042/////////////////////////////////////////////////////////////////// 043//// HammingCoder 044 045/** 046 Encode the information symbols into Hamming code. 047 Let <i>k</i> denotes parameter <i>uncodedRate</i> and <i>n</i> denotes 048 parameter <i>codedRate</i>. During each firing, the actor consumes 049 <i>k</i> bits and encode them into a block of code with length <i>n</i>. 050 The rate of the code is <i>k/n</i>. 051 <p> 052 For a Hamming code, <i>k</i> and <i>n</i> must satisfy the following: 053 <i>n</i> = 2<i><sup>m</sup></i> - 1 054 <i>k</i> = 2<sup><i>m</i></sup> - 1 - <i>m</i>; 055 where <i>m</i> is any positive integer. Note <i>m</i> = <i>n</i> - <i>k</i>. 056 It is called the order of the Hamming code. The lowest order is <i>m</i> = 2, 057 and (<i>n</i>, <i>k</i>) = (3, 1). 058 <p> 059 The generator matrix G is defined as: 060 G<i><sub>k*n</sub></i> = [I<i><sub>k</sub></i> | P<i><sub>k*(n-k)</sub></i> ] 061 where P is called the parity matrix. 062 The subscript of a matrix indicates its dimension. 063 <p> 064 The parity check matrix H is defined as: 065 H<sub><i>(n-k)*n</i></sub> = [P<sup>T</sup> | I<sub><i>n-k</i></sub> ] 066 Each column of H must be one of the non-zero <i>n</i> = 2<sup><i>m</i></sup> - 1 067 combinations of <i>m</i> bits. 068 <p> 069 To generate a Hamming code, the <i>k</i> information bits is considered 070 as a row vector <i><u>X</u></i>. Its Hamming code is 071 <i><u>Y</u></i> = <i><u>X</u></i> * G. 072 Hence <i><u>Y</u></i> is a row vector of length <i>n</i>. The result is 073 then sent to the output port in sequence. 074 <p> 075 For more information on Hamming codes, see Proakis, Digital 076 Communications, Fourth Edition, McGraw-Hill, 2001, pp. 416-424. 077 <p> 078 @author Ye Zhou 079 @version $Id$ 080 @since Ptolemy II 3.0 081 @Pt.ProposedRating Red (eal) 082 @Pt.AcceptedRating Red (cxh) 083 */ 084public class HammingCoder extends Transformer { 085 /** Construct an actor with the given container and name. 086 * The output and trigger ports are also constructed. 087 * @param container The container. 088 * @param name The name of this actor. 089 * @exception IllegalActionException If the entity cannot be contained 090 * by the proposed container. 091 * @exception NameDuplicationException If the container already has an 092 * actor with this name. 093 */ 094 public HammingCoder(CompositeEntity container, String name) 095 throws NameDuplicationException, IllegalActionException { 096 super(container, name); 097 098 uncodedRate = new Parameter(this, "uncodedRate"); 099 uncodedRate.setTypeEquals(BaseType.INT); 100 uncodedRate.setExpression("4"); 101 102 codedRate = new Parameter(this, "codedRate"); 103 codedRate.setTypeEquals(BaseType.INT); 104 codedRate.setExpression("7"); 105 106 // Declare data types, consumption rate and production rate. 107 input.setTypeEquals(BaseType.BOOLEAN); 108 _inputRate = new Parameter(input, "tokenConsumptionRate", 109 new IntToken(1)); 110 output.setTypeEquals(BaseType.BOOLEAN); 111 _outputRate = new Parameter(output, "tokenProductionRate", 112 new IntToken(1)); 113 } 114 115 /////////////////////////////////////////////////////////////////// 116 //// ports and parameters //// 117 118 /** Integer defining the uncode block size. It should be a positive 119 * integer. Its default value is the integer 4. 120 */ 121 public Parameter uncodedRate; 122 123 /** Integer defining the Hamming code block size. 124 * This parameter should be a non-negative integer. 125 * Its default value is the integer 7. 126 */ 127 public Parameter codedRate; 128 129 /////////////////////////////////////////////////////////////////// 130 //// public methods //// 131 132 /** If the attribute being changed is <i>uncodedRate</i> or 133 * <i>uncodedRate</i>, then verify that it is a positive integer. 134 * Set the tokenConsumptionRate and tokenProductionRate. 135 * @param attribute The attribute that changed. 136 * @exception IllegalActionException If <i>codedRate</i> 137 * or <i>uncodedRate</i> is not positive. 138 */ 139 @Override 140 public void attributeChanged(Attribute attribute) 141 throws IllegalActionException { 142 if (attribute == codedRate) { 143 _codeSizeValue = ((IntToken) codedRate.getToken()).intValue(); 144 145 if (_codeSizeValue <= 0) { 146 throw new IllegalActionException(this, 147 "codedRate must be positive."); 148 } 149 150 // set the output production rate. 151 _outputRate.setToken(new IntToken(_codeSizeValue)); 152 } else if (attribute == uncodedRate) { 153 _uncodeSizeValue = ((IntToken) uncodedRate.getToken()).intValue(); 154 155 if (_uncodeSizeValue < 1) { 156 throw new IllegalActionException(this, 157 "uncodedRate must be non-negative."); 158 } 159 160 // Set a flag indicating the private variables 161 // _uncodeSizeValue and/or _codeSizeValue is invalid, 162 // but do not compute the value until all parameters 163 // have been set. 164 _parameterInvalid = true; 165 166 // Set the input consumption rate. 167 _inputRate.setToken(new IntToken(_uncodeSizeValue)); 168 } else { 169 super.attributeChanged(attribute); 170 } 171 } 172 173 /** Clone the actor into the specified workspace. 174 * @param workspace The workspace for the new object. 175 * @return A new actor. 176 * @exception CloneNotSupportedException If a derived class contains 177 * an attribute that cannot be cloned. 178 */ 179 @Override 180 public Object clone(Workspace workspace) throws CloneNotSupportedException { 181 HammingCoder newObject = (HammingCoder) super.clone(workspace); 182 183 newObject._inputRate = (Parameter) newObject.input 184 .getAttribute("tokenConsumptionRate"); 185 newObject._outputRate = (Parameter) newObject.output 186 .getAttribute("tokenProductionRate"); 187 return newObject; 188 } 189 190 /** If the attributes has changed, check the validity of 191 * uncodedRate and codedRate. Generate the parity matrix. 192 * Read "uncodedRate" number of tokens from the input port 193 * and compute the parities. Send the parities in sequence to the 194 * output port. 195 */ 196 @Override 197 public void fire() throws IllegalActionException { 198 super.fire(); 199 if (_parameterInvalid) { 200 if (_uncodeSizeValue >= _codeSizeValue) { 201 throw new IllegalActionException(this, 202 "codedRate must be greater than uncodedRate."); 203 } 204 205 _order = _codeSizeValue - _uncodeSizeValue; 206 207 if (_codeSizeValue != (1 << _order) - 1) { 208 throw new IllegalActionException(this, 209 "Invalid pair of uncodedRate and codedRate."); 210 } 211 212 // Generate P. 213 _parityMatrix = new int[_uncodeSizeValue][_order]; 214 215 int flag = 0; 216 int index = 0; 217 218 for (int i = 1; i <= _codeSizeValue; i++) { 219 if (i == 1 << flag) { 220 flag++; 221 } else { 222 for (int j = 0; j < _order; j++) { 223 _parityMatrix[index][j] = i >> _order - j - 1 & 1; 224 } 225 226 index++; 227 } 228 } 229 230 _parameterInvalid = false; 231 } 232 233 // Read from the input; set up output size. 234 Token[] inputToken = input.get(0, _uncodeSizeValue); 235 BooleanToken[] result = new BooleanToken[_codeSizeValue]; 236 237 for (int i = 0; i < _uncodeSizeValue; i++) { 238 result[i] = (BooleanToken) inputToken[i]; 239 } 240 241 // Compute parities. 242 int[] parity = new int[_order]; 243 244 // Initialize. 245 for (int i = 0; i < _order; i++) { 246 parity[i] = 0; 247 } 248 249 for (int i = 0; i < _uncodeSizeValue; i++) { 250 for (int j = 0; j < _order; j++) { 251 parity[j] = parity[j] ^ (result[i].booleanValue() ? 1 : 0) 252 & _parityMatrix[i][j]; 253 } 254 } 255 256 // Send the parity results to the output. 257 for (int i = 0; i < _order; i++) { 258 result[i + _uncodeSizeValue] = new BooleanToken(parity[i] == 1); 259 } 260 261 output.broadcast(result, result.length); 262 } 263 264 /////////////////////////////////////////////////////////////////// 265 //// private variables //// 266 // Consumption rate of the input port. 267 private Parameter _inputRate; 268 269 // Production rate of the output port. 270 private Parameter _outputRate; 271 272 // Uncode block length. 273 private int _uncodeSizeValue; 274 275 // Hamming codeword length. 276 private int _codeSizeValue; 277 278 // Order of the Hamming code. 279 private int _order; 280 281 // matrix "P" for this Hamming code. 282 private int[][] _parityMatrix; 283 284 // A flag indicating that the private variable 285 // _inputNumber is invalid. 286 private transient boolean _parameterInvalid = true; 287}