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}