001/* Downsample a stream by the 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//// DownSample
040
041/**
042 This actor downsamples an input stream by an integer factor by
043 removing tokens.  The downsample factor is given by the <i>factor</i>
044 parameter. On each firing, this actor consumes <i>factor</i> tokens from the
045 input and sends only one of them to the output.  The one sent
046 depends on the <i>phase</i> parameter.  If <i>phase</i> is 0, then
047 the most recent one (the last one consumed) is sent.  If <i>phase</i>
048 is 1, then the next most recent one is sent. The value of <i>phase</i>
049 can range up to <i>factor</i>-1, in which case the first one consumed
050 is sent. By default, the <i>factor</i> parameter is 2,
051 so the input sample rate is twice that of the output.
052 The default value for <i>phase</i> is 0.
053 <p>
054 This actor is data polymorphic. It can accept any token
055 type on the input.
056
057 @see UpSample
058 @author Steve Neuendorffer, Edward A. Lee
059 @version $Id$
060 @since Ptolemy II 1.0
061 @Pt.ProposedRating Yellow (neuendor)
062 @Pt.AcceptedRating Yellow (neuendor)
063 */
064public class DownSample extends SDFTransformer {
065    /** Construct an actor with the given container and name.
066     *  @param container The container.
067     *  @param name The name of this actor.
068     *  @exception IllegalActionException If the actor cannot be contained
069     *   by the proposed container.
070     *  @exception NameDuplicationException If the container already has an
071     *   actor with this name.
072     */
073    public DownSample(CompositeEntity container, String name)
074            throws NameDuplicationException, IllegalActionException {
075        super(container, name);
076
077        // Set parameters.
078        factor = new Parameter(this, "factor");
079        factor.setExpression("2");
080
081        phase = new Parameter(this, "phase");
082        phase.setExpression("0");
083
084        input_tokenConsumptionRate.setExpression("factor");
085    }
086
087    ///////////////////////////////////////////////////////////////////
088    ////                         parameters                        ////
089
090    /** The number of input tokens to read per output token produced.
091     *  This is an integer that defaults to 2 and must be greater than
092     *  zero.
093     */
094    public Parameter factor;
095
096    /** The phase of the output with respect to the input.
097     *  This is an integer that defaults to 0 and must be between 0
098     *  and <i>factor</i>-1. If <i>phase</i> = 0, the most recent
099     *  sample is the output, while if <i>phase</i> = <i>factor</i>-1
100     *  the oldest sample is the output.
101     */
102    public Parameter phase;
103
104    ///////////////////////////////////////////////////////////////////
105    ////                         public methods                    ////
106
107    /** Ensure that the factor and phase parameters are both positive.
108     *  @param attribute The attribute that has changed.
109     *  @exception IllegalActionException If the parameters are out of range.
110     */
111    @Override
112    public void attributeChanged(Attribute attribute)
113            throws IllegalActionException {
114        if (attribute == factor) {
115            int factorValue = ((IntToken) factor.getToken()).intValue();
116
117            if (factorValue <= 0) {
118                throw new IllegalActionException(this,
119                        "Invalid factor: " + factorValue);
120            }
121        } else if (attribute == phase) {
122            int phaseValue = ((IntToken) phase.getToken()).intValue();
123
124            if (phaseValue < 0) {
125                throw new IllegalActionException(this,
126                        "Invalid phase: " + phaseValue);
127            }
128        } else {
129            super.attributeChanged(attribute);
130        }
131    }
132
133    /** Consume <i>factor</i> tokens from the input, and select one of
134     *  them to send to the output based on the <i>phase</i>.
135     *  @exception IllegalActionException If there is no director, or
136     *   if the <i>phase</i> value is out of range.
137     */
138    @Override
139    public void fire() throws IllegalActionException {
140        super.fire();
141
142        int factorValue = ((IntToken) factor.getToken()).intValue();
143        Token[] valueArray = input.get(0, factorValue);
144
145        int phaseValue = ((IntToken) phase.getToken()).intValue();
146
147        if (phaseValue >= factorValue) {
148            throw new IllegalActionException(this,
149                    "Phase is out of range: " + phaseValue);
150        }
151
152        // Send the token.
153        output.send(0, valueArray[factorValue - phaseValue - 1]);
154    }
155}