001/* An actor that hold the last event and outputs a constant signal. 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.continuous.lib; 029 030import java.util.HashSet; 031import java.util.Set; 032 033import ptolemy.actor.lib.Transformer; 034import ptolemy.data.Token; 035import ptolemy.data.expr.Parameter; 036import ptolemy.domains.continuous.kernel.ContinuousDirector; 037import ptolemy.graph.Inequality; 038import ptolemy.kernel.CompositeEntity; 039import ptolemy.kernel.util.IllegalActionException; 040import ptolemy.kernel.util.InternalErrorException; 041import ptolemy.kernel.util.NameDuplicationException; 042 043/////////////////////////////////////////////////////////////////// 044//// ZeroOrderHold 045 046/** 047 Convert discrete events at the input to a continuous-time 048 signal at the output by holding the value of the discrete 049 event until the next discrete event arrives. Specifically, 050 on each firing, if an input is present, then record the 051 value of the input. Then produce the recorded value. 052 Prior to receipt of the first input, output the token 053 given by <i>defaultValue</i>, if one is given. 054 This actor will throw an exception if the input is not 055 purely discrete. Specifically, this means that when the input 056 is present, the step size of the solver has to be 0.0. 057 058 @author Edward A. Lee, Haiyang Zheng 059 @version $Id$ 060 @since Ptolemy II 6.0 061 @Pt.ProposedRating Green (hyzheng) 062 @Pt.AcceptedRating Red (hyzheng) 063 */ 064public class ZeroOrderHold extends Transformer { 065 /** Construct an actor in the specified container with the specified 066 * name. The name must be unique within the container or an exception 067 * is thrown. The container argument must not be null, or a 068 * NullPointerException will be thrown. 069 * 070 * @param container The subsystem that this actor is lived in 071 * @param name The actor's name 072 * @exception IllegalActionException If the entity cannot be contained 073 * by the proposed container. 074 * @exception NameDuplicationException If name coincides with 075 * an entity already in the container. 076 */ 077 public ZeroOrderHold(CompositeEntity container, String name) 078 throws IllegalActionException, NameDuplicationException { 079 super(container, name); 080 defaultValue = new Parameter(this, "defaultValue"); 081 082 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-20\" " 083 + "width=\"60\" height=\"40\" " + "style=\"fill:white\"/>\n" 084 + "<polyline points=\"-25,10 -15,10 -15,-10 5,-10\"/>\n" 085 + "<polyline points=\"5,-10 5,0 15,0 15,10 25,10\"/>\n" 086 + "</svg>\n"); 087 } 088 089 /////////////////////////////////////////////////////////////////// 090 //// ports and parameters //// 091 092 /** Default output before any input has received. 093 * The default is empty, indicating 094 * that no output is produced until an input is received. 095 * The type of the output is set to at least the type of 096 * this parameter (and also at least the type of the input). 097 */ 098 public Parameter defaultValue; 099 100 /////////////////////////////////////////////////////////////////// 101 //// public methods //// 102 103 /** Output the latest token consumed from the consumeCurrentEvents() 104 * call. 105 * @exception IllegalActionException If the token cannot be sent. 106 */ 107 @Override 108 public void fire() throws IllegalActionException { 109 super.fire(); 110 111 if (input.hasToken(0)) { 112 ContinuousDirector dir = (ContinuousDirector) getDirector(); 113 double stepSize = dir.getCurrentStepSize(); 114 if (stepSize != 0.0 && !_firstFiring) { 115 throw new IllegalActionException(this, 116 "Signal at the input port is not purely discrete."); 117 } 118 _lastToken = input.get(0); 119 if (_debugging) { 120 _debug("Input value " + _lastToken + " read at time " 121 + dir.getModelTime() + " and microstep " 122 + dir.getIndex()); 123 } 124 } 125 if (_lastToken != null) { 126 output.send(0, _lastToken); 127 if (_debugging) { 128 ContinuousDirector dir = (ContinuousDirector) getDirector(); 129 _debug("Output value " + _lastToken + " sent at time " 130 + dir.getModelTime() + " and microstep " 131 + dir.getIndex()); 132 } 133 } 134 } 135 136 /** Initialize token. If there is no input, the initial token is 137 * a Double Token with the value specified by the defaultValue parameter. 138 * @exception IllegalActionException If thrown by the super class. 139 */ 140 @Override 141 public void initialize() throws IllegalActionException { 142 super.initialize(); 143 _lastToken = defaultValue.getToken(); 144 _firstFiring = true; 145 } 146 147 /** Override the base class to record that the first firing 148 * has completed. 149 * @return True if execution can continue into the next iteration. 150 * @exception IllegalActionException If the base class throws it. 151 */ 152 @Override 153 public boolean postfire() throws IllegalActionException { 154 _firstFiring = false; 155 return super.postfire(); 156 } 157 158 /////////////////////////////////////////////////////////////////// 159 //// protected methods //// 160 161 /** 162 * Return a constraint that requires the type of the <i>defaultValue</i> 163 * parameter to be less than or equal to the type of the <i>output</i> 164 * port. 165 */ 166 @Override 167 protected Set<Inequality> _customTypeConstraints() { 168 Set<Inequality> result = new HashSet<Inequality>(); 169 try { 170 // type of initialValue <= type of output 171 if (defaultValue.getToken() != null) { 172 result.add(new Inequality(defaultValue.getTypeTerm(), 173 output.getTypeTerm())); 174 } 175 } catch (IllegalActionException ex) { 176 // Errors in the defaultValue parameter should already 177 // have been caught in getAttribute() method of the base 178 // class. 179 throw new InternalErrorException("Bad defaultValue!\n" + ex); 180 } 181 182 return result; 183 } 184 185 /////////////////////////////////////////////////////////////////// 186 //// private variables //// 187 188 /** Saved token. */ 189 private Token _lastToken; 190 191 /** Indicator that this is the first firing after initialize(). */ 192 private boolean _firstFiring; 193}