001/* An interpolator for a specified array of indexes and values. 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.actor.lib; 029 030import ptolemy.data.ArrayToken; 031import ptolemy.data.DoubleToken; 032import ptolemy.data.IntToken; 033import ptolemy.data.expr.Parameter; 034import ptolemy.data.type.ArrayType; 035import ptolemy.data.type.BaseType; 036import ptolemy.kernel.CompositeEntity; 037import ptolemy.kernel.util.Attribute; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.Workspace; 041import ptolemy.math.Interpolation; 042 043/////////////////////////////////////////////////////////////////// 044//// Interpolator 045 046/** 047 <p>Produce an interpolation based on the parameters. 048 This class uses the Interpolation class in the math package to compute 049 the interpolation. 050 The <i>values</i> parameter specifies a sequence of values 051 to produce at the output. The <i>indexes</i> parameter specifies 052 when those values should be produced. 053 The values and indexes parameters must both contain 054 arrays, and have equal lengths or an exception will be thrown. 055 The <i>indexes</i> array must be increasing and non-negative. 056 The values are periodic if the <i>period</i> parameter contains a 057 positive value. In this case, the period must be greater than the 058 largest index, and values within the index range 0 to (period-1) are 059 repeated indefinitely. If the period is zero, the values are not 060 periodic, and the values outside the range of the indexes are 061 considered to be 0.0. The <i>order</i> parameter 062 specifies which order of interpolation to apply whenever the 063 iteration count does not match an index in <i>indexes</i>. 064 The Interpolation class currently supports zero, first, and third 065 order interpolations. The default parameter are those set in the 066 Interpolation class.</p> 067 <p> 068 This actor counts iterations. Whenever the iteration count matches an entry 069 in the <i>indexes</i> array, the corresponding entry (at the same position) 070 in the <i>values</i> array is produced at the output. Whenever the iteration 071 count does not match a value in the <i>indexes</i> array, an interpolation 072 of the values is produced at the output.</p> 073 <p> 074 Output type is DoubleToken.</p> 075 076 @author Sarah Packman, Yuhong Xiong 077 @version $Id$ 078 @since Ptolemy II 0.3 079 @Pt.ProposedRating Yellow (yuhong) 080 @Pt.AcceptedRating Yellow (yuhong) 081 @see ptolemy.math.Interpolation 082 */ 083public class Interpolator extends SequenceSource { 084 /** Construct an actor with the specified container and name. 085 * @param container The container. 086 * @param name The name of this actor. 087 * @exception IllegalActionException If the entity cannot be contained 088 * by the proposed container. 089 * @exception NameDuplicationException If the container already has an 090 * actor with this name. 091 */ 092 public Interpolator(CompositeEntity container, String name) 093 throws NameDuplicationException, IllegalActionException { 094 super(container, name); 095 096 _interpolation = new Interpolation(); 097 098 // Initialize the parameters with the default settings of the 099 // Interpolation class. This is not required for this class to 100 // function. But since these parameters are public, other objects 101 // in the system may use them. 102 indexes = new Parameter(this, "indexes"); 103 indexes.setExpression("{0, 1}"); 104 indexes.setTypeEquals(new ArrayType(BaseType.INT)); 105 106 // Call this so that we don't have to copy its code here... 107 attributeChanged(indexes); 108 109 // set values parameter 110 values = new Parameter(this, "values"); 111 values.setExpression("{1.0, 0.0}"); 112 values.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 113 114 int defOrder = _interpolation.getOrder(); 115 IntToken defOrderToken = new IntToken(defOrder); 116 order = new Parameter(this, "order", defOrderToken); 117 order.setTypeEquals(BaseType.INT); 118 119 int defPeriod = _interpolation.getPeriod(); 120 IntToken defPeriodToken = new IntToken(defPeriod); 121 period = new Parameter(this, "period", defPeriodToken); 122 period.setTypeEquals(BaseType.INT); 123 124 output.setTypeEquals(BaseType.DOUBLE); 125 126 // Show the firingCountLimit parameter last. 127 firingCountLimit.moveToLast(); 128 } 129 130 /////////////////////////////////////////////////////////////////// 131 //// public variables //// 132 133 /** The indexes at which the specified values will be produced. 134 * This parameter is an array of integers, with default value {0, 1}. 135 */ 136 public Parameter indexes; 137 138 /** The order of interpolation for non-index iterations. 139 * This parameter must contain an IntToken. 140 */ 141 public Parameter order; 142 143 /** The period of the reference values. 144 * This parameter must contain an IntToken. 145 */ 146 public Parameter period; 147 148 /** The values that will be produced at the specified indexes. 149 * This parameter is an array, with default value {1.0, 0.0}. 150 */ 151 public Parameter values; 152 153 /////////////////////////////////////////////////////////////////// 154 //// public methods //// 155 156 /** Check the validity of the parameter. 157 * @param attribute The attribute that changed. 158 * @exception IllegalActionException If the argument is the 159 * <i>values</i> parameter and it does not contain an one dimensional 160 * array; or the argument is the <i>indexes</i> parameter and it does 161 * not contain an one dimensional array or is not increasing and 162 * non-negative; or the argument is the <i>period</i> parameter and is 163 * negative; or the argument is the <i>order</i> parameter and the order 164 * is not supported by the Interpolation class. 165 */ 166 @Override 167 public void attributeChanged(Attribute attribute) 168 throws IllegalActionException { 169 if (attribute == values) { 170 ArrayToken valuesValue = (ArrayToken) values.getToken(); 171 _values = new double[valuesValue.length()]; 172 173 for (int i = 0; i < valuesValue.length(); i++) { 174 _values[i] = ((DoubleToken) valuesValue.getElement(i)) 175 .doubleValue(); 176 } 177 178 _interpolation.setValues(_values); 179 } else if (attribute == indexes) { 180 ArrayToken indexesValue = (ArrayToken) indexes.getToken(); 181 _indexes = new int[indexesValue.length()]; 182 183 int previous = 0; 184 185 for (int i = 0; i < indexesValue.length(); i++) { 186 _indexes[i] = ((IntToken) indexesValue.getElement(i)) 187 .intValue(); 188 189 // Check nondecreasing property. 190 if (_indexes[i] < previous) { 191 throw new IllegalActionException(this, 192 "Value of indexes is not nondecreasing " 193 + "and nonnegative."); 194 } 195 196 previous = _indexes[i]; 197 } 198 199 _interpolation.setIndexes(_indexes); 200 } else if (attribute == period) { 201 int newPeriod = ((IntToken) period.getToken()).intValue(); 202 _interpolation.setPeriod(newPeriod); 203 } else if (attribute == order) { 204 int newOrder = ((IntToken) order.getToken()).intValue(); 205 _interpolation.setOrder(newOrder); 206 } else { 207 super.attributeChanged(attribute); 208 } 209 } 210 211 /** Clone the actor into the specified workspace. This calls the 212 * base class and then initializes private variables. 213 * public members to the parameters of the new actor. 214 * @param workspace The workspace for the new object. 215 * @return A new actor. 216 * @exception CloneNotSupportedException If a derived class contains 217 * an attribute that cannot be cloned. 218 */ 219 @Override 220 public Object clone(Workspace workspace) throws CloneNotSupportedException { 221 Interpolator newObject = (Interpolator) super.clone(workspace); 222 223 newObject._indexes = new int[_indexes.length]; 224 System.arraycopy(_indexes, 0, newObject._indexes, 0, _indexes.length); 225 226 newObject._interpolation = new Interpolation(); 227 228 if (_values == null) { 229 newObject._values = null; 230 } else { 231 newObject._values = new double[_values.length]; 232 System.arraycopy(_values, 0, newObject._values, 0, _values.length); 233 } 234 return newObject; 235 } 236 237 /** Output the value at the current iteration count. The output is 238 * one of the reference values if the iteration count matches one 239 * of the indexes, or is interpolated otherwise. 240 * @exception IllegalActionException If the <i>values</i> and 241 * <i>indexes</i> parameters do not contain arrays of the same length, 242 * or the period is not 0 and not greater than the largest index. 243 */ 244 @Override 245 public void fire() throws IllegalActionException { 246 super.fire(); 247 248 double result = _interpolation.interpolate(_iterationCount); 249 output.send(0, new DoubleToken(result)); 250 } 251 252 /** Set the iteration count to zero. 253 * @exception IllegalActionException If the super class throws it. 254 */ 255 @Override 256 public void initialize() throws IllegalActionException { 257 super.initialize(); 258 _iterationCount = 0; 259 } 260 261 /** Update the iteration counter, then call the super class method. 262 * @return A boolean returned by the super class method. 263 * @exception IllegalActionException If the super class throws it. 264 */ 265 @Override 266 public boolean postfire() throws IllegalActionException { 267 ++_iterationCount; 268 return super.postfire(); 269 } 270 271 /////////////////////////////////////////////////////////////////// 272 //// private variables //// 273 // Cache of indexes array value. 274 private transient int[] _indexes; 275 276 private int _iterationCount = 0; 277 278 private Interpolation _interpolation; 279 280 // Cache of values array value. 281 private transient double[] _values; 282}