001/* Viterbi Decoder. 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.TypeAttribute; 031import ptolemy.actor.lib.Transformer; 032import ptolemy.data.ArrayToken; 033import ptolemy.data.BooleanToken; 034import ptolemy.data.ComplexToken; 035import ptolemy.data.DoubleToken; 036import ptolemy.data.IntToken; 037import ptolemy.data.Token; 038import ptolemy.data.expr.Parameter; 039import ptolemy.data.type.ArrayType; 040import ptolemy.data.type.BaseType; 041import ptolemy.kernel.CompositeEntity; 042import ptolemy.kernel.util.Attribute; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.NameDuplicationException; 045import ptolemy.kernel.util.Settable; 046import ptolemy.kernel.util.Workspace; 047import ptolemy.math.Complex; 048 049/////////////////////////////////////////////////////////////////// 050//// ViterbiDecoder 051 052/** 053 The Viterbi algorithm is an optimal way to decode convolutional and 054 trellis codes. The code is specified jointly by the <i>uncodedRate</i> 055 and <i>polynomialArray</i> parameters. To get a <i>k</i>/<i>n</i> 056 code, set <i>uncodedRate</i> to <i>k</i> and give <i>n</i> integers 057 in <i>polynomialArray</i>. See ConvolutionalCoder for details about 058 the meaning of these parameters. On each firing, this actor will 059 read <i>n</i> inputs and produce <i>k</i> outputs. 060 <p> 061 The decoder finds the most likely data sequence given noisy inputs 062 by searching all possibilities and computing the distance 063 between the codewords they produce and the observed noisy data. 064 The sequence yielding the minimum distance is the decoded output. 065 <p> 066 There are two choices offered in this actor to compute the distance. 067 If it the parameter <i>softDecoding</i> is set to be false, the input 068 port will accept boolean tokens and compute the Hamming distance. 069 If the parameter <i>softDecoding</i> is set to be true, the input port 070 will accept double tokens and compute the Euclidean distance. 071 The parameter <i>constellation</i> should be a double array of length 2. 072 The first element specifies the amplitude of "false" input. The second 073 element specifies the amplitude of "true" input. At this time, 074 this actor can only handle binary antipodal constellations, but 075 we expect to generalize this. 076 <p> 077 Soft decoding has lower probability of decoding error than hard decoding. 078 But distance computation for hard decoding is easier, since it is based 079 on bit operations. Moreover, hard decoding can be used when there is no 080 direct observation of the noisy data, but only observations of a bit 081 sequence that may have errors in it. With hard decoding, this 082 actor serves the role of correcting errors. With soft decoding, it 083 serves the role of reducing the likelyhood of errors. 084 <p> 085 There is some delay between the reading of input data and the 086 production of decoded output data. That delay, which is called 087 the <i>trace-back depth</i> or <i>truncation depth</i> of the 088 decoder, is controlled by the 089 <i>delay</i> parameter, which is required to be a positive integer. 090 On the first <i>delay</i> firings of this actor, the outputs will 091 be <i>false</i>. On each firing, the number of outputs produced 092 is <i>uncodedRate</i>, so the output will have a prefix of 093 <i>delay</i>*<i>uncodedRate</i> false-valued tokens before any 094 decoded bits are produced. Larger values of <i>delay</i> generally 095 reduce the probability of error. A good rule of thumb is to set 096 <i>delay</i> to five times the highest order of all polynomials, provided 097 that the convolutional code is a one that has good distance properties. 098 <p> 099 For more information on convolutional codes and Viterbi decoder, 100 see the ConvolutionalCoder actor and 101 Proakis, <i>Digital Communications</i>, Fourth Edition, McGraw-Hill, 102 2001, pp. 471-477 and pp. 482-485, 103 or Barry, Lee and Messerschmitt, <i>Digital Communication</i>, Third Edition, 104 Kluwer, 2004. 105 <p> 106 @author Ye Zhou, contributor: Edward A. Lee 107 @version $Id$ 108 @since Ptolemy II 3.0 109 @Pt.ProposedRating Yellow (eal) 110 @Pt.AcceptedRating Red (cxh) 111 */ 112public class ViterbiDecoder extends Transformer { 113 /** Construct an actor with the given container and name. 114 * The output and trigger ports are also constructed. 115 * @param container The container. 116 * @param name The name of this actor. 117 * @exception IllegalActionException If the entity cannot be contained 118 * by the proposed container. 119 * @exception NameDuplicationException If the container already has an 120 * actor with this name. 121 */ 122 public ViterbiDecoder(CompositeEntity container, String name) 123 throws NameDuplicationException, IllegalActionException { 124 super(container, name); 125 126 uncodedRate = new Parameter(this, "uncodedRate"); 127 uncodedRate.setTypeEquals(BaseType.INT); 128 uncodedRate.setExpression("1"); 129 130 polynomialArray = new Parameter(this, "polynomialArray"); 131 polynomialArray.setTypeEquals(new ArrayType(BaseType.INT)); 132 polynomialArray.setExpression("{05, 07}"); 133 134 delay = new Parameter(this, "delay"); 135 delay.setTypeEquals(BaseType.INT); 136 delay.setExpression("10"); 137 138 softDecoding = new Parameter(this, "softDecoding"); 139 softDecoding.setExpression("false"); 140 softDecoding.setTypeEquals(BaseType.BOOLEAN); 141 142 trellisDecoding = new Parameter(this, "trellisDecoding"); 143 trellisDecoding.setExpression("false"); 144 trellisDecoding.setTypeEquals(BaseType.BOOLEAN); 145 trellisDecoding.setVisibility(Settable.NONE); 146 147 constellation = new Parameter(this, "constellation"); 148 constellation.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 149 constellation.setExpression("{-1.0, 1.0}"); 150 151 //mode = new StringAttribute(this, "mode"); 152 //mode.setExpression("Hard Decoding"); 153 //mode.setVisibility(Settable.NONE); 154 // Declare data types, consumption rate and production rate. 155 _type = new ptolemy.actor.TypeAttribute(input, "inputType"); 156 _type.setExpression("boolean"); 157 _inputRate = new Parameter(input, "tokenConsumptionRate"); 158 _inputRate.setExpression("1"); 159 output.setTypeEquals(BaseType.BOOLEAN); 160 _outputRate = new Parameter(output, "tokenProductionRate"); 161 _outputRate.setExpression("1"); 162 } 163 164 /////////////////////////////////////////////////////////////////// 165 //// ports and parameters //// 166 167 /** An array of integers defining polynomials with 168 * binary coefficients. The coefficients indicate the presence (1) 169 * or absence (0) of a tap in the shift register. Each element 170 * of this array parameter should be a positive integer. 171 * The default value is {05, 07}. 172 */ 173 public Parameter polynomialArray; 174 175 /** Integer defining the number of bits produced at the output 176 * in each firing. It should be a positive integer. Its 177 * default value is 1. 178 */ 179 public Parameter uncodedRate; 180 181 /** Integer defining the trace back depth of the viterbi decoder. 182 * It should be a positive integer. Its default value is the 183 * integer 10. 184 */ 185 public Parameter delay; 186 187 /** Boolean defining the decoding mode. If it is true, the decoder 188 * will do soft decoding, and the input data type will be double; 189 * otherwise it will do hard decoding, and the input data type will 190 * be boolean. The default value is false. 191 */ 192 public Parameter softDecoding; 193 194 /** Boolean defining whether the decoder will do trellis decoding. 195 * If it is true, the input data and constellation type will be 196 * complex; otherwise, they follow the constraints set by 197 * <i>softDecoding</i>. This parameter is always set to "false" 198 * in ViterbiDecoder. It will always be set to "true" in 199 * TrellisDecoder subclass. 200 */ 201 public Parameter trellisDecoding; 202 203 /** The constellation for soft decoding. Inputs are expected to be 204 * symbols from this constellation with added noise. 205 * This parameter should be a double array of length 2. The first 206 * element defines the amplitude of "false" input. The second element 207 * defines the amplitude of "true" input. 208 */ 209 public Parameter constellation; 210 211 //public StringAttribute mode; 212 /////////////////////////////////////////////////////////////////// 213 //// public methods //// 214 215 /** If the attribute being changed is <i>softDecoding</i> or 216 * <i>trellisDecoding</i>, set input port and constellation 217 * type to be complex if <i>trellisDecoding</i> is true; else 218 * if <i>softDecoding</i> is true, set them to double type; 219 * otherwise set the input port to type boolean. 220 * If the attribute being changed is <i>uncodedRate</i> or 221 * <i>delay</i> then verify it is a positive integer; if it is 222 * <i>polynomialArray</i>, then verify that each of its elements 223 * is a positive integer. 224 * @param attribute The attribute that changed. 225 * @exception IllegalActionException If <i>uncodedRate</i>, 226 * or <i>delay</i> is non-positive, or any element of 227 * <i>polynomialArray</i> is non-positive. 228 */ 229 @Override 230 public void attributeChanged(Attribute attribute) 231 throws IllegalActionException { 232 /*if (attribute == mode) { 233 String modeName = mode.getExpression(); 234 if (modeName.equals("Hard Decoding")) { 235 //_mode = _HARD; 236 //_type.setExpression("boolean"); 237 } else if (modeName.equals("Soft Decoding")) { 238 //_mode = _SOFT; 239 //_type.setExpression("double"); 240 //constellation.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 241 } else if (modeName.equals("Trellis Decoding")) { 242 //_mode = _TRELLIS; 243 //_type.setExpression("complex"); 244 //constellation.setTypeEquals(new ArrayType(BaseType.COMPLEX)); 245 } 246 else { 247 throw new IllegalActionException(this, 248 "Unrecognized interpolation type: " + modeName); 249 } 250 } else */ 251 if (attribute == softDecoding || attribute == trellisDecoding) { 252 _trellisMode = ((BooleanToken) trellisDecoding.getToken()) 253 .booleanValue(); 254 _softMode = ((BooleanToken) softDecoding.getToken()).booleanValue(); 255 256 // Set different input port types for soft and hard decoding. 257 if (_trellisMode) { 258 _mode = _TRELLIS; 259 _type.setExpression("complex"); 260 constellation.setTypeEquals(new ArrayType(BaseType.COMPLEX)); 261 } else if (_softMode) { 262 _mode = _SOFT; 263 _type.setExpression("double"); 264 constellation.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 265 } else { 266 _mode = _HARD; 267 _type.setExpression("boolean"); 268 } 269 } else if (attribute == uncodedRate) { 270 _inputNumber = ((IntToken) uncodedRate.getToken()).intValue(); 271 272 if (_inputNumber < 1) { 273 throw new IllegalActionException(this, 274 "inputLength must be non-negative."); 275 } 276 277 // Set a flag indicating the private variable 278 // _inputNumber is invalid, but do not compute 279 // the value until all parameters have been set. 280 _inputNumberInvalid = true; 281 282 // Set the input consumption rate. 283 _outputRate.setToken(new IntToken(_inputNumber)); 284 } else if (attribute == delay) { 285 _depth = ((IntToken) delay.getToken()).intValue(); 286 287 if (_depth < 1) { 288 throw new IllegalActionException(this, 289 "Delay must be a positive integer."); 290 } 291 292 _depthInvalid = true; 293 } else if (attribute == polynomialArray) { 294 ArrayToken maskToken = (ArrayToken) polynomialArray.getToken(); 295 _maskNumber = maskToken.length(); 296 _mask = new int[_maskNumber]; 297 _maxPolyValue = 0; 298 299 for (int i = 0; i < _maskNumber; i++) { 300 _mask[i] = ((IntToken) maskToken.getElement(i)).intValue(); 301 302 if (_mask[i] <= 0) { 303 throw new IllegalActionException(this, 304 "Polynomial is required to be strictly positive."); 305 } 306 307 // Find maximum value in integer of all polynomials. 308 if (_mask[i] > _maxPolyValue) { 309 _maxPolyValue = _mask[i]; 310 } 311 } 312 313 _inputNumberInvalid = true; 314 315 // Set the output production rate. 316 boolean trellisMode = ((BooleanToken) trellisDecoding.getToken()) 317 .booleanValue(); 318 319 if (trellisMode) { 320 _inputRate.setToken(new IntToken(1)); 321 } else { 322 _inputRate.setToken(new IntToken(_maskNumber)); 323 } 324 } else { 325 super.attributeChanged(attribute); 326 } 327 } 328 329 /** Clone the actor into the specified workspace. 330 * @param workspace The workspace for the new object. 331 * @return A new actor. 332 * @exception CloneNotSupportedException If a derived class contains 333 * an attribute that cannot be cloned. 334 */ 335 @Override 336 public Object clone(Workspace workspace) throws CloneNotSupportedException { 337 ViterbiDecoder newObject = (ViterbiDecoder) super.clone(workspace); 338 339 newObject._inputRate = (Parameter) newObject.input 340 .getAttribute("tokenConsumptionRate"); 341 newObject._mask = new int[newObject._maskNumber]; 342 newObject._outputRate = (Parameter) newObject.output 343 .getAttribute("tokenProductionRate"); 344 newObject._type = (TypeAttribute) newObject.input 345 .getAttribute("inputType"); 346 return newObject; 347 } 348 349 /** Read <i>n</i> inputs and produce <i>k</i> outputs, where <i>n</i> 350 * is the number of integers in <i>polynomialArray</i> and <i>k</i> 351 * is the value of the <i>uncodedRate</i> parameter. The outputs 352 * are a decoded bit sequence, with a prefix of <i>false</i>-valued 353 * tokens produced on the first <i>delay</i> firings. The number 354 * of leading <i>false</i> outputs, therefore, is 355 * <i>delay</i>*<i>uncodedRate</i>. 356 * To decode, the actor searches iteratively of all possible 357 * input sequence and find the one that has the minimum distance 358 * to the observed inputs. 359 */ 360 @Override 361 public void fire() throws IllegalActionException { 362 super.fire(); 363 //boolean trellisMode = 364 // ((BooleanToken)trellisDecoding.getToken()).booleanValue(); 365 int constellationOrder; 366 int inputRate; 367 368 if (_mode == _TRELLIS) { 369 constellationOrder = _maskNumber; 370 inputRate = 1; 371 } else { 372 constellationOrder = 1; 373 inputRate = _maskNumber; 374 } 375 376 if (_mode == _TRELLIS) { 377 _constellation = new Complex[1 << constellationOrder]; 378 379 ArrayToken ampToken = (ArrayToken) constellation.getToken(); 380 381 if (ampToken.length() != 1 << constellationOrder) { 382 throw new IllegalActionException(this, 383 "Invalid amplitudes for soft decoding!"); 384 } 385 386 for (int i = 0; i < ampToken.length(); i++) { 387 _constellation[i] = ((ComplexToken) ampToken.getElement(i)) 388 .complexValue(); 389 } 390 } else if (_mode == _SOFT) { 391 ArrayToken ampToken = (ArrayToken) constellation.getToken(); 392 393 if (ampToken.length() != 1 << constellationOrder) { 394 throw new IllegalActionException(this, 395 "Invalid amplitudes for soft decoding!"); 396 } 397 398 _falseAmp = ((DoubleToken) ampToken.getElement(0)).doubleValue(); 399 _trueAmp = ((DoubleToken) ampToken.getElement(1)).doubleValue(); 400 } 401 402 // If the private variable _inputNumberInvalid is true, verify 403 // the validity of the parameters. If they are valid, compute 404 // the state-transition table of this convolutional code, which 405 // is stored in a 3-D array _truthTable[][][]. 406 if (_inputNumberInvalid) { 407 if (_inputNumber >= _maskNumber) { 408 throw new IllegalActionException(this, 409 "Output rate should be larger than input rate."); 410 } 411 412 //Comput the length of shift register. 413 _shiftRegLength = 0; 414 415 int regLength = 1; 416 417 while (regLength <= _maxPolyValue) { 418 //regLength = regLength << _inputNumber; 419 //_shiftRegLength = _shiftRegLength + _inputNumber; 420 regLength = regLength << 1; 421 _shiftRegLength++; 422 } 423 424 if (_inputNumber >= _shiftRegLength) { 425 throw new IllegalActionException(this, 426 "The highest order of all polynomials is " 427 + "still too low."); 428 } 429 430 _inputNumberInvalid = false; 431 432 // Compute the necessary dimensions for the truth table and 433 // the length of buffers used to store possible input sequence. 434 _rowNum = 1 << _shiftRegLength - _inputNumber; 435 _colNum = 1 << _inputNumber; 436 _truthTable = new int[_rowNum][_colNum][3]; 437 _distance = new double[_rowNum]; 438 _tempDistance = new double[_rowNum]; 439 440 // Initialize the truth table and the buffer. 441 for (int i = 0; i < _rowNum; i++) { 442 _distance[i] = 0; 443 _tempDistance[i] = 0; 444 } 445 446 int inputMask = (1 << _inputNumber) - 1; 447 448 // Compute the truth table. 449 // _truthTable[m][n][1:3] has the following meanings: 450 // "m" is the possible current state of the shift register. 451 // It has 2<sup>k</sup> possible previous states, where "k" 452 // is the <i>uncodedRate</i>. 453 // Hence _truthTable[m][n][1:3] stores the truth values for 454 // the n-th possible previous state for state "m". 455 // _truthTable[m][n][1] is the "value" of the previous 456 // shift register's states. 457 // _truthTable[m][n][2] is the corresponding input block. 458 // _truthTable[m][n][0] is the corresponding codewords 459 // produced from the encoder. 460 for (int state = 0; state < _rowNum; state++) { 461 for (int head = 0; head < _colNum; head++) { 462 int reg = head << _shiftRegLength - _inputNumber; 463 reg = reg + state; 464 465 int[] parity = _calculateParity(_mask, _maskNumber, reg); 466 int outValue = 0; 467 468 // store the output values as an integer 469 // in the order of yn...y1y0 470 for (int i = _maskNumber - 1; i >= 0; i--) { 471 outValue = outValue << 1; 472 outValue = outValue + parity[i]; 473 } 474 475 _truthTable[state][head][0] = outValue; 476 477 int oldState = reg >> _inputNumber; 478 _truthTable[state][head][1] = oldState; 479 480 int input = reg & inputMask; 481 _truthTable[state][head][2] = input; 482 } 483 } 484 } 485 486 if (_depthInvalid) { 487 _path = new int[_rowNum][_depth + 1]; 488 _tempPath = new int[_rowNum][_depth + 1]; 489 490 for (int i = 0; i < _rowNum; i++) { 491 for (int j = 0; j < _depth; j++) { 492 _path[i][j] = 0; 493 _tempPath[i][j] = 0; 494 } 495 } 496 497 _depthInvalid = false; 498 } 499 500 // Read from the input port. 501 Token[] inputToken = input.get(0, inputRate); 502 503 // Search the optimal path (minimum distance) for each state. 504 for (int state = 0; state < _rowNum; state++) { 505 double minDistance = 0; 506 int minInput = 0; 507 int minState = 0; 508 509 for (int colIndex = 0; colIndex < _colNum; colIndex++) { 510 // Compute the distance for each possible path to "state". 511 double d = 0.0; 512 513 if (_mode == _TRELLIS) { 514 Complex y = ((ComplexToken) inputToken[0]).complexValue(); 515 d = _computeTrellisDistance(y, _constellation, 516 _truthTable[state][colIndex][0]); 517 } else if (_mode == _SOFT) { 518 double[] y = new double[inputRate]; 519 520 for (int i = 0; i < inputRate; i++) { 521 y[i] = ((DoubleToken) inputToken[i]).doubleValue(); 522 } 523 524 d = _computeSoftDistance(y, _falseAmp, _trueAmp, 525 _truthTable[state][colIndex][0], inputRate); 526 } else { 527 boolean[] y = new boolean[_maskNumber]; 528 529 for (int i = 0; i < _maskNumber; i++) { 530 y[i] = ((BooleanToken) inputToken[i]).booleanValue(); 531 } 532 533 d = _computeHardDistance(y, _truthTable[state][colIndex][0], 534 _maskNumber); 535 } 536 537 // The previous state for that possibility. 538 int oldState = _truthTable[state][colIndex][1]; 539 d = _tempDistance[oldState] + d; 540 541 // Find the minimum distance and corresponding previous 542 // state for each possible current state of the shift register. 543 if (colIndex == 0 || d < minDistance) { 544 minDistance = d; 545 minState = oldState; 546 minInput = _truthTable[state][colIndex][2]; 547 } 548 } 549 550 // update the buffers for minimum distance and its 551 // corresponding possible input sequence. 552 _distance[state] = minDistance; 553 554 for (int i = 0; i < _flag; i++) { 555 _path[state][i] = _tempPath[minState][i]; 556 } 557 558 _path[state][_flag] = minInput; 559 } 560 561 // Send all-false tokens for the first "D" firings. 562 // If the waiting time has reached "D", the decoder starts to send 563 // the decoded bits to the output port. 564 if (_flag < _depth) { 565 BooleanToken[] initialOutput = new BooleanToken[_inputNumber]; 566 567 for (int i = 0; i < _inputNumber; i++) { 568 initialOutput[i] = BooleanToken.FALSE; 569 } 570 571 output.broadcast(initialOutput, _inputNumber); 572 } else { 573 // make a "final" decision among minimum distances of all states. 574 double minD = 0; 575 int minIndex = 0; 576 577 for (int state = 0; state < _rowNum; state++) { 578 if (state == 0 || _distance[state] < minD) { 579 minD = _distance[state]; 580 minIndex = state; 581 } 582 } 583 584 // Cast the decoding result into booleans and 585 // send them in sequence to the output. 586 BooleanToken[] decoded = new BooleanToken[_inputNumber]; 587 decoded = _convertToBit(_path[minIndex][0], _inputNumber); 588 output.broadcast(decoded, _inputNumber); 589 590 // Discard those datum in the buffers which have already 591 // been made a "final" decision on. Move the rest datum 592 // to the front of the buffers. 593 for (int state = 0; state < _rowNum; state++) { 594 for (int i = 0; i < _flag; i++) { 595 _path[state][i] = _path[state][i + 1]; 596 } 597 } 598 599 _flag = _flag - 1; 600 } 601 602 _flag = _flag + 1; 603 } 604 605 /** Initialize the actor. 606 * @exception IllegalActionException If the parent class throws it. 607 */ 608 @Override 609 public void initialize() throws IllegalActionException { 610 super.initialize(); 611 _inputNumberInvalid = true; 612 _flag = 0; 613 } 614 615 /** Record the datum in buffers into their temporary versions. 616 * @exception IllegalActionException If the base class throws it 617 */ 618 @Override 619 public boolean postfire() throws IllegalActionException { 620 // Copy datum in buffers to their temp versions. 621 for (int i = 0; i < _rowNum; i++) { 622 _tempDistance[i] = _distance[i]; 623 624 for (int j = 0; j < _flag; j++) { 625 _tempPath[i][j] = _path[i][j]; 626 } 627 } 628 629 return super.postfire(); 630 } 631 632 /////////////////////////////////////////////////////////////////// 633 //// private methods //// 634 635 /** Calculate the parity given by the polynomial and the 636 * state of shift register. 637 * @param mask Polynomial. 638 * @param maskNumber Number of polynomials. 639 * @param reg State of shift register. 640 * @return Parity. 641 */ 642 private int[] _calculateParity(int[] mask, int maskNumber, int reg) { 643 int[] parity = new int[maskNumber]; 644 645 for (int i = 0; i < maskNumber; i++) { 646 int masked = mask[i] & reg; 647 648 // Find the parity of the "masked". 649 parity[i] = 0; 650 651 // Calculate the parity of the masked word. 652 while (masked > 0) { 653 parity[i] = parity[i] ^ masked & 1; 654 masked = masked >> 1; 655 } 656 } 657 658 return parity; 659 } 660 661 /** Compute the Hamming distance given by the datum received from 662 * the input port and the value in the truthTable. 663 * @param y Array of the booleans received from the input port. 664 * @param truthValue integer representing the truth value 665 * from the truth table. 666 * @param maskNum The length of "y" and "truthValue". 667 * @return The distance. 668 */ 669 private int _computeHardDistance(boolean[] y, int truthValue, int maskNum) { 670 int hammingDistance = 0; 671 672 for (int i = 0; i < maskNum; i++) { 673 int truthBit = truthValue & 1; 674 truthValue = truthValue >> 1; 675 676 // Compute Hamming distance for hard decoding. 677 hammingDistance = hammingDistance + ((y[i] ? 1 : 0) ^ truthBit); 678 } 679 680 return hammingDistance; 681 } 682 683 /** Compute the Euclidean distance given by the datum received from 684 * the input port and the value in the truthTable. 685 * @param y Array of the double-type numbers received from 686 * the input port. 687 * @param falseAmp Amplitude of "false" input. 688 * @param trueAmp Amplitude of "true" input. 689 * @param truthValue integer representing the truth value 690 * from the truth table. 691 * @param inputRate The length of "y" and "truthValue". 692 * @return The distance. 693 */ 694 private double _computeSoftDistance(double[] y, double falseAmp, 695 double trueAmp, int truthValue, int inputRate) { 696 /*if (trellisMode) { 697 Complex truthComplex = constellation[truthValue]; 698 Complex z = truthComplex.subtract(y[0].complexValue()); 699 return z.magnitudeSquared(); 700 } else {*/ 701 double distance = 0.0; 702 double truthAmp; 703 704 for (int i = 0; i < inputRate; i++) { 705 int truthBit = truthValue & 1; 706 707 if (truthBit == 1) { 708 truthAmp = trueAmp; 709 } else { 710 truthAmp = falseAmp; 711 } 712 713 // Euclidean distance for soft decoding. Here we 714 // actually compute the square of the Euclidean distance. 715 distance = distance + java.lang.Math.pow(y[i] - truthAmp, 2); 716 717 truthValue = truthValue >> 1; 718 } 719 720 return distance; 721 } 722 723 /** Compute the Euclidean distance given by the datum received 724 * from the input port and the value in the truthTable in 725 * trellis decoding mode. 726 * @param y Complex number received from the input port. 727 * @param constellation Complex array defining the constellation. 728 * @param truthValue integer representing the truth value 729 * from the truth table. 730 * @return The distance. 731 */ 732 private double _computeTrellisDistance(Complex y, Complex[] constellation, 733 int truthValue) { 734 Complex truthComplex = constellation[truthValue]; 735 736 //Complex z = y; 737 Complex v = truthComplex.subtract(y); 738 return v.magnitudeSquared(); 739 } 740 741 /** Convert an integer to its binary form. The bits 742 * are stored in an array. 743 * @param integer The integer to be converted. 744 * @param length The length of "integer" in binary form. 745 * @return The bits of "integer" stored in an array. 746 */ 747 private BooleanToken[] _convertToBit(int integer, int length) { 748 BooleanToken[] bit = new BooleanToken[length]; 749 750 for (int i = length - 1; i >= 0; i--) { 751 if ((integer & 1) == 1) { 752 bit[i] = BooleanToken.TRUE; 753 } else { 754 bit[i] = BooleanToken.FALSE; 755 } 756 757 integer = integer >> 1; 758 } 759 760 return bit; 761 } 762 763 /////////////////////////////////////////////////////////////////// 764 //// private parameters and variables //// 765 // Consumption rate of the input port. 766 private Parameter _inputRate; 767 768 // Production rate of the output port. 769 private Parameter _outputRate; 770 771 // Input port type. 772 private TypeAttribute _type; 773 774 // Decoding mode. 775 private boolean _trellisMode; 776 777 private boolean _softMode; 778 779 private int _mode; 780 781 // Amplitudes for soft decoding. 782 private double _trueAmp; 783 784 private double _falseAmp; 785 786 private Complex[] _constellation; 787 788 // Number bits the actor consumes per firing. 789 private int _inputNumber; 790 791 // Number of polynomials. 792 private int _maskNumber; 793 794 // Polynomial array. 795 private int[] _mask; 796 797 // The maximum value in integer among all polynomials. 798 // It is used to compute the necessary shift register's length. 799 private int _maxPolyValue; 800 801 // Length of the shift register. 802 private int _shiftRegLength = 0; 803 804 // A flag indicating that the private variable 805 // _inputNumber is invalid. 806 private transient boolean _inputNumberInvalid = true; 807 808 // A flag indicating that the the private variable 809 // _depth is invalid. 810 private transient boolean _depthInvalid = true; 811 812 // Truth table for the corresponding convolutional code. 813 private int[][][] _truthTable; 814 815 // Size of first dimension of the truth table. 816 private int _rowNum; 817 818 // Size of second dimension of the truth table. 819 private int _colNum; 820 821 // The delay specified by the user. 822 private int _depth; 823 824 // Buffers for minimum distance, possible input sequence 825 // for each state. And their temporary versions used 826 // when updating. 827 private double[] _distance; 828 829 private double[] _tempDistance; 830 831 private int[][] _path; 832 833 private int[][] _tempPath; 834 835 // A flag used to indicate the positions that new values 836 // should be inserted in the buffers. 837 private int _flag; 838 839 private static final int _HARD = 0; 840 841 private static final int _SOFT = 1; 842 843 private static final int _TRELLIS = 2; 844}