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}