Logo Search packages:      
Sourcecode: vat version File versions

rate-variable.cc

/*
 * Copyright (c) 1995 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Computer Systems
 *    Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
static const char rcsid[] =
    "@(#) $Header: rate-variable.cc,v 1.4 96/03/16 13:13:56 van Exp $ (LBL)";

#include <stdlib.h>
#include "sys-time.h"
#include "Tcl.h"

/*
 * The following command & the associate service procedure
 * creates a `rate variable'.  Reading a rate variable returns
 * the time rate of change of its value.  Writing a rate variable
 * updates the rate of change estimate.  A rate variable can be
 * either simple or an array element.  It must be global.  This
 * routine is called as:
 *    rate_variable varname filter_const
 * where 'varname' is the variable name (e.g., "foo" or "foo(bar)")
 * and 'filter_const' is a smoothing constant for the rate estimate.
 * It should be >0 and <1 (a value of 1 will result in no smoothing).
 */
struct rv_data {
      double rate;
      double filter;
      timeval lastupdate;
      int lastval;
      char format[16];
};

class RateVariable : public TclObject {
public:
      RateVariable(const char* name) : TclObject(name) { }
protected:
      static char* update_rate_var(ClientData, Tcl_Interp*, const char* name1,
                             const char* name2, int flags);
      int command(int argc, const char*const* argv);
} rate_variable_cmd("rate_variable");

char* RateVariable::update_rate_var(ClientData clientData, Tcl_Interp* tcl,
                            const char* name1, const char* name2, int flags)
{
      rv_data* rv = (rv_data*)clientData;
      if (rv == NULL)
            return ("no clientdata for rate var");
      if (flags & TCL_TRACE_WRITES) {
            /*
             * the variable has been written with a new value.
             * compute the rate of change & make that its vale
             * for subsequent reads.
             */
            char res[128];
            flags &= TCL_GLOBAL_ONLY;
            const char* cv = Tcl_GetVar2(tcl, name1, name2, flags);
            if (cv == NULL)
                  return (tcl->result);
            int curval = atoi(cv);
            double rate = 0.;
            timeval tv;
            gettimeofday(&tv, 0);
            if (rv->lastupdate.tv_sec != 0) {
                  /* not first time through */
                  double dt = double(tv.tv_sec - rv->lastupdate.tv_sec) +
                            double(tv.tv_usec -
                              rv->lastupdate.tv_usec) * 1e-6;
                  if (dt <= 0.)
                        /* have to wait until next clock tick */
                        return NULL;
                  double dv = double(curval - rv->lastval);
                  if (dv >= 0.) {
                        rate = rv->rate;
                        rate += (dv/dt - rate) * rv->filter;
                        /* work around tcl f.p. precision bug */
                        if (rate < 1e-12)
                              rate = 0.;
                  }
            }
            rv->rate = rate;
            rv->lastupdate = tv;
            rv->lastval = curval;
            sprintf(res, rv->format, rate);
            Tcl_SetVar2(tcl, name1, name2, res, flags);
      } else if (flags & (TCL_TRACE_DESTROYED|TCL_INTERP_DESTROYED)) {
            delete rv;
      }
      return NULL;
}

int RateVariable::command(int argc, const char *const*argv)
{
      Tcl& tcl = Tcl::instance();
      const char* fmt;
      if (argc == 4)
            fmt = argv[3];
      else if (argc == 3)
            fmt = "%g";
      else {
            tcl.result("usage: rate_variable varname filter_const");
            return (TCL_ERROR);
      }
      double fconst = atof(argv[2]);
      if (fconst <= 0. || fconst > 1.) {
            tcl.result("rate_variable: invalid filter constant");
            return (TCL_ERROR);
      }
      rv_data* rv = new rv_data;
      rv->filter = fconst;
      rv->rate = 0.;
      rv->lastupdate.tv_sec = 0;
      rv->lastval = 0;
      strcpy(rv->format, fmt);
      int sts = Tcl_TraceVar(tcl.interp(), (char*)argv[1],
                  TCL_TRACE_WRITES|TCL_TRACE_UNSETS|TCL_GLOBAL_ONLY,
                  update_rate_var, (ClientData)rv);
      if (sts != TCL_OK)
            delete rv;
      return (sts);
}

Generated by  Doxygen 1.6.0   Back to index