001/* Upsample a signal by a specified amount.
002
003 Copyright (c) 1998-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.domains.sdf.lib;
029
030import ptolemy.data.IntToken;
031import ptolemy.data.Token;
032import ptolemy.data.expr.Parameter;
033import ptolemy.kernel.CompositeEntity;
034import ptolemy.kernel.util.Attribute;
035import ptolemy.kernel.util.IllegalActionException;
036import ptolemy.kernel.util.NameDuplicationException;
037
038///////////////////////////////////////////////////////////////////
039//// UpSample
040
041/**
042 This actor upsamples an input stream by an integer factor by inserting
043 tokens with value zero.  The upsample factor is given by the
044 <i>factor</i> parameter. On each firing, this actor reads one
045 token from the input produces <i>factor</i> tokens on the output
046 port.  All but one of these is a zero-valued token of the same type
047 as the input.  The remaining one is the token read from the input.
048 The position of this remaining one is determined by the <i>phase</i>
049 parameter.  This parameter has a value between 0 and <i>factor</i>-1.
050 If it is 0, then the input token is the first output token, followed
051 by zeros. If it is <i>factor</i>-1, then it is the last output.
052 Thus, if this actor is followed by the DownSample actor with the same
053 <i>factor</i>, and the two <i>phase</i> parameters have a sum of
054 <i>factor</i>-1, the combination has no effect.
055 <p>
056 By default, <i>factor</i> is 2, and <i>phase</i> is the expression
057 "factor-1".  This means that by default, the input token that is read
058 is the last one produced at the output.
059 <p>
060 This actor is data polymorphic. It can accept any token
061 type on the input that supports the zero() method,
062 and it sends output tokens of that type.
063
064 @see DownSample
065 @author Steve Neuendorffer, Edward A. Lee
066 @version $Id$
067 @since Ptolemy II 1.0
068 @Pt.ProposedRating Yellow (neuendor)
069 @Pt.AcceptedRating Yellow (eal)
070 */
071public class UpSample extends SDFTransformer {
072    /** Construct an actor with the given container and name.
073     *  @param container The container.
074     *  @param name The name of this actor.
075     *  @exception IllegalActionException If the actor cannot be contained
076     *   by the proposed container.
077     *  @exception NameDuplicationException If the container already has an
078     *   actor with this name.
079     */
080    public UpSample(CompositeEntity container, String name)
081            throws NameDuplicationException, IllegalActionException {
082        super(container, name);
083
084        // Set parameters.
085        factor = new Parameter(this, "factor");
086        factor.setExpression("2");
087        phase = new Parameter(this, "phase");
088        phase.setExpression("factor-1");
089
090        output_tokenProductionRate.setExpression("factor");
091    }
092
093    ///////////////////////////////////////////////////////////////////
094    ////                         parameters                        ////
095
096    /** The number of output tokens to produced per input token read.
097     *  This is an integer that defaults to 2 and must be greater than
098     *  zero.
099     */
100    public Parameter factor;
101
102    /** The phase of the output with respect to the input.
103     *  This is an integer that defaults to <i>factor</i>-1 and must be
104     *  between 0 and <i>factor</i>-1. If <i>phase</i> = 0, the input
105     *  is the first output, while if <i>phase</i> = <i>factor</i>-1
106     *  then the input is the last output.
107     */
108    public Parameter phase;
109
110    ///////////////////////////////////////////////////////////////////
111    ////                         public methods                    ////
112
113    /** Ensure that the factor and phase parameters are both positive.
114     *  @param attribute The attribute that has changed.
115     *  @exception IllegalActionException If the parameters are out of range.
116     */
117    @Override
118    public void attributeChanged(Attribute attribute)
119            throws IllegalActionException {
120        if (attribute == factor) {
121            int factorValue = ((IntToken) factor.getToken()).intValue();
122
123            if (factorValue <= 0) {
124                throw new IllegalActionException(this,
125                        "Invalid factor: " + factorValue);
126            }
127        } else if (attribute == phase) {
128            int phaseValue = ((IntToken) phase.getToken()).intValue();
129
130            if (phaseValue < 0) {
131                throw new IllegalActionException(this,
132                        "Invalid phase: " + phaseValue);
133            }
134        } else {
135            super.attributeChanged(attribute);
136        }
137    }
138
139    /** Consume the input Token and produce the same token on the output.
140     *  Then create a number of zero tokens of the same type as the
141     *  input token on the output port, so that output.tokenProductionRate
142     *  tokens are created in total.  If there is not token on the input,
143     *  then this method throws a NoTokenException (which is a runtime
144     *  exception).
145     *  @exception IllegalActionException If a runtime type conflict occurs.
146     */
147    @Override
148    public void fire() throws IllegalActionException {
149        super.fire();
150
151        Token token = input.get(0);
152        int factorValue = ((IntToken) factor.getToken()).intValue();
153        int phaseValue = ((IntToken) phase.getToken()).intValue();
154
155        if (phaseValue >= factorValue) {
156            throw new IllegalActionException(this,
157                    "Phase is out of range: " + phaseValue);
158        }
159
160        Token[] result = new Token[factorValue];
161        Token zero = token.zero();
162
163        for (int i = 0; i < factorValue; i++) {
164            if (i == phaseValue) {
165                result[i] = token;
166            } else {
167                result[i] = zero;
168            }
169        }
170
171        if (_debugging) {
172            StringBuffer resultString = new StringBuffer("[");
173            for (Token resultToken : result) {
174                if (resultString.length() != 1) {
175                    resultString.append(", ");
176                }
177                resultString.append(resultToken.toString());
178            }
179            resultString.append("]");
180            _debug("Sending to output: " + resultString);
181        }
182        output.send(0, result, factorValue);
183    }
184}