001/* Generate discrete events by sampling a CT 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.actor.lib; 029 030import ptolemy.actor.TypedIOPort; 031import ptolemy.data.Token; 032import ptolemy.kernel.CompositeEntity; 033import ptolemy.kernel.util.IllegalActionException; 034import ptolemy.kernel.util.NameDuplicationException; 035import ptolemy.kernel.util.StringAttribute; 036import ptolemy.kernel.util.Workspace; 037 038/////////////////////////////////////////////////////////////////// 039//// Sampler 040 041/** 042 This actor generates discrete events by sampling the input signal whenever 043 the <i>trigger</i> input is present. 044 This sampler will send to the output whatever input occurs 045 at a sample time; if the input is absent, the output will be 046 absent. 047 <p> 048 This actor has multiport inputs and outputs. Signals in 049 each input channel are sampled and produced to corresponding output 050 channel. When there are multiple inputs, the first non-absent input 051 from each channel is read, and the output is produced at the first 052 microstep after the last of the inputs became non-absent. 053 054 @author Edward A. Lee 055 @version $Id$ 056 @since Ptolemy II 8.0 057 @Pt.ProposedRating Yellow (eal) 058 @Pt.AcceptedRating Red (cxh) 059 */ 060public class Sampler extends Transformer { 061 /** Construct an actor in the specified container with the specified 062 * name. The name must be unique within the container or an exception 063 * is thrown. The container argument must not be null, or a 064 * NullPointerException will be thrown. 065 * The actor can be either dynamic, or not. It must be set at the 066 * construction time and can't be changed thereafter. 067 * A dynamic actor will produce a token at its initialization phase. 068 * @param container The container of this actor. 069 * @param name The actor's name 070 * @exception IllegalActionException If the entity cannot be contained 071 * by the proposed container. 072 * @exception NameDuplicationException If name coincides with 073 * an entity already in the container. 074 */ 075 public Sampler(CompositeEntity container, String name) 076 throws IllegalActionException, NameDuplicationException { 077 super(container, name); 078 input.setMultiport(true); 079 output.setMultiport(true); 080 output.setWidthEquals(input, true); 081 082 output.setTypeSameAs(input); 083 084 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-20\" " 085 + "width=\"60\" height=\"40\" " + "style=\"fill:white\"/>\n" 086 + "<polyline points=\"-30,0 -20,0 -10,0 10,-7\"/>\n" 087 + "<polyline points=\"10,0 30,0\"/>\n" + "</svg>\n"); 088 089 trigger = new TypedIOPort(this, "trigger", true, false); 090 trigger.setMultiport(true); 091 092 // Width constraint. Not bidirectional to not break any existing models. 093 output.setWidthEquals(input, true); 094 095 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-20\" " 096 + "width=\"60\" height=\"40\" " + "style=\"fill:white\"/>\n" 097 + "<polyline points=\"0,20 0,0\"/>\n" 098 + "<polyline points=\"-30,-0 -10,0 10,-7\"/>\n" 099 + "<polyline points=\"10,0 30,0\"/>\n" + "</svg>\n"); 100 101 StringAttribute cardinality = new StringAttribute(trigger, "_cardinal"); 102 cardinality.setExpression("SOUTH"); 103 } 104 105 /////////////////////////////////////////////////////////////////// 106 //// ports and parameters //// 107 108 /** The trigger port, which has undeclared type. If this port 109 * receives a token, then the most recent token from the 110 * <i>input</i> port will be emitted on the <i>output</i> port. 111 */ 112 public TypedIOPort trigger; 113 114 /////////////////////////////////////////////////////////////////// 115 //// public methods //// 116 117 /** Clone this actor into the specified workspace. The new actor is 118 * <i>not</i> added to the directory of that workspace (you must do this 119 * yourself if you want it there). 120 * The result is a new actor with the same ports as the original, but 121 * no connections and no container. A container must be set before 122 * much can be done with this actor. 123 * 124 * @param workspace The workspace for the cloned object. 125 * @exception CloneNotSupportedException If cloned ports cannot have 126 * as their container the cloned entity (this should not occur), or 127 * if one of the attributes cannot be cloned. 128 * @return A new ComponentEntity. 129 */ 130 @Override 131 public Object clone(Workspace workspace) throws CloneNotSupportedException { 132 Sampler newObject = (Sampler) super.clone(workspace); 133 newObject.output.setTypeSameAs(newObject.input); 134 newObject.output.setWidthEquals(newObject.input, true); 135 136 return newObject; 137 } 138 139 /** Generate an output if the current time is one of the sampling 140 * times. The value of the event is the value of the input signal at the 141 * current time. 142 * @exception IllegalActionException If the transfer of tokens failed. 143 */ 144 @Override 145 public void fire() throws IllegalActionException { 146 super.fire(); 147 148 boolean hasTrigger = false; 149 for (int i = 0; i < trigger.getWidth(); i++) { 150 if (trigger.hasToken(i)) { 151 trigger.get(i); 152 hasTrigger = true; 153 } 154 } 155 156 // Read the input and send it to the output if a trigger has arrived. 157 int width = Math.min(input.getWidth(), output.getWidth()); 158 for (int i = 0; i < input.getWidth(); i++) { 159 if (input.hasToken(i)) { 160 Token token = input.get(i); 161 if (hasTrigger) { 162 if (_debugging) { 163 _debug("Sampled input value " + token + " at time " 164 + getDirector().getModelTime()); 165 } 166 if (i < width) { 167 output.send(i, token); 168 } 169 } 170 } 171 } 172 } 173}