Qucs-core  0.0.19
tswitch.cpp
Go to the documentation of this file.
00001 /*
00002  * tswitch.cpp - time controlled switch class implementation
00003  *
00004  * Copyright (C) 2006, 2008 Stefan Jahn <stefan@lkcc.org>
00005  *
00006  * This is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2, or (at your option)
00009  * any later version.
00010  *
00011  * This software is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this package; see the file COPYING.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  * $Id$
00022  *
00023  */
00024 
00034 #if HAVE_CONFIG_H
00035 # include <config.h>
00036 #endif
00037 
00038 #include <iostream>
00039 #include <cmath>
00040 #include "component.h"
00041 #include "tswitch.h"
00042 
00043 using namespace qucs;
00044 
00045 tswitch::tswitch () : circuit (2) {
00046   type = CIR_TSWITCH;
00047   setVoltageSources (1);
00048 }
00049 
00050 nr_double_t tswitch::initState (void) {
00051   const char * const init = getPropertyString ("init");
00052   bool on = !strcmp (init, "on");
00053   return on ? getPropertyDouble ("Ron") : getPropertyDouble ("Roff");
00054 }
00055 
00056 void tswitch::initSP (void) {
00057   nr_double_t r = initState ();
00058   allocMatrixS ();
00059   setS (NODE_1, NODE_1, r / (r + 2));
00060   setS (NODE_2, NODE_2, r / (r + 2));
00061   setS (NODE_1, NODE_2, 2 / (r + 2));
00062   setS (NODE_2, NODE_1, 2 / (r + 2));
00063 }
00064 
00065 void tswitch::calcNoiseSP (nr_double_t) {
00066   nr_double_t T = getPropertyDouble ("Temp");
00067   nr_double_t r = initState ();
00068   nr_double_t f = celsius2kelvin (T) * 4.0 * r * z0 / sqr (2.0 * z0 + r) / T0;
00069   setN (NODE_1, NODE_1, +f); setN (NODE_2, NODE_2, +f);
00070   setN (NODE_1, NODE_2, -f); setN (NODE_2, NODE_1, -f);
00071 }
00072 
00073 void tswitch::calcNoiseAC (nr_double_t) {
00074   nr_double_t r = initState ();
00075   if (r > 0.0 || r < 0.0) {
00076     nr_double_t T = getPropertyDouble ("Temp");
00077     nr_double_t f = celsius2kelvin (T) / T0 * 4.0 / r;
00078     setN (NODE_1, NODE_1, +f); setN (NODE_2, NODE_2, +f);
00079     setN (NODE_1, NODE_2, -f); setN (NODE_2, NODE_1, -f);
00080   }
00081 }
00082 
00083 void tswitch::initDC (void) {
00084   nr_double_t r = initState ();
00085   allocMatrixMNA ();
00086   voltageSource (VSRC_1, NODE_1, NODE_2);
00087   setD (VSRC_1, VSRC_1, -r);
00088 }
00089 
00090 void tswitch::initAC (void) {
00091   initDC ();
00092 }
00093 
00094 void tswitch::initTR (void) {
00095   qucs::vector * values = getPropertyVector ("time");
00096   // Find the total time of the switching periods
00097   T = real (sum (*values));
00098   // if the user enters an even number of switching times
00099   // the pattern is repeated continuously
00100   repeat = (values->getSize () % 2) == 0 ? true : false;
00101   // make the time taken to go from fully on to fully off
00102   // the smallest switching time / 100, or the smallest possible
00103   // number, but no bigger than the max specified duration
00104   nr_double_t maxduration = getPropertyDouble("MaxDuration");
00105   duration = std::min ( std::max (10*NR_TINY, values->minimum() / 100),
00106                         maxduration );
00107   initDC ();
00108 }
00109 
00110 void tswitch::calcTR (nr_double_t t) {
00111   const char * const init = getPropertyString ("init");
00112   nr_double_t ron = getPropertyDouble ("Ron");
00113   nr_double_t roff = getPropertyDouble ("Roff");
00114   const char * const trans_type = getPropertyString ("Transition");
00115   nr_double_t r = 0;
00116   nr_double_t rdiff = 0;
00117   //nr_double_t s_i = 0;
00118   nr_double_t r_0 = 0;
00119   qucs::vector * values = getPropertyVector ("time");
00120   bool on = !strcmp (init, "on");
00121   nr_double_t ti = 0;
00122 
00123   if (repeat) {
00124     // if the user enters an even number of switching times
00125     // the pattern is repeated continuously. This is achieved by
00126     // subtracting an integer number of total switching periods
00127     // from the real time
00128     t = t - T * qucs::floor (t / T);
00129   }
00130 
00131   // Initialise the last switching time to be well in the past
00132   // to avoid having the switch even partially in a transition
00133   // state (due to inaccurately computed time differences)
00134   nr_double_t ts = -2*duration;
00135 
00136   // here we determine whether a switching event should occur
00137   // by looping through the list of switching times and comparing
00138   // to the current time
00139   for (int i = 0; i < values->getSize (); i++) {
00140     // add the current value from the list of switching times
00141     // to a counter
00142     ti += real (values->get (i));
00143 
00144     if (t >= ti)
00145     {
00146       // the current time is greater than or equal to the current
00147       // sum of switching times so the switch state changes
00148       on = !on;
00149       // store the current switching time
00150       ts = ti;
00151     }
00152     else {
00153       // the current sum of switching times is in the future
00154       // so exit the loop
00155       break;
00156     }
00157   }
00158 
00159   if (!strcmp(trans_type, "abrupt")) {
00160     r = (on ? ron : roff);
00161   } else {
00162     // calculate the time since the last switch occurred
00163     nr_double_t tdiff = std::max(NR_TINY, t - ts);
00164     
00165     // set the time difference to be no more than the max switch
00166     // duration so when we interpolate below we only get the max
00167     // or min function value if we are past a switching time
00168     if (tdiff > duration) {
00169       tdiff = duration;
00170     }
00171     // Set the appropriate resistance. 
00172     if (on) {
00173       r_0 = roff;
00174       rdiff = ron - roff;
00175       //    s_i = (rdiff) / (duration);
00176     } else {
00177       r_0 = ron;
00178       rdiff = roff - ron;
00179       //  s_i = (rdiff) / (duration);
00180     }
00181     if (!strcmp(trans_type, "linear")) {
00182       // simple linear transition over the transition time
00183       r = r_0 + rdiff * tdiff / duration;
00184     } else { // assume trans_type is "spline"
00185         // the resistance is interpolated along a constrained cubic spline
00186         // with zero derivative at the start and end points to ensure a 
00187         // smooth derivative
00188         //r = r_0 + ((3. * s_i * qucs::pow (tdiff,2.0)) / (duration))
00189         //        + ((-2. * s_i * qucs::pow (tdiff,3.0)) / qucs::pow (duration, 2.0));
00190         // use Horner's rule to reduce the numerical errors
00191         r = r_0 + (((-2. * rdiff * tdiff / duration) + 3. * rdiff) * qucs::pow(tdiff/duration, 2.0));
00192       }
00193   }
00194 
00195   // check for (numerical) errors
00196   assert(r >= ron);
00197   assert(r <= roff);
00198 
00199   setD (VSRC_1, VSRC_1, -r);
00200 }
00201 
00202 // properties
00203 PROP_REQ [] = {
00204   { "init", PROP_STR, { PROP_NO_VAL, "off" }, PROP_RNG_STR2 ("on", "off") },
00205   { "time", PROP_LIST, { 1e-9, PROP_NO_STR }, PROP_POS_RANGE },
00206   PROP_NO_PROP };
00207 PROP_OPT [] = {
00208   { "Ron", PROP_REAL, { 0, PROP_NO_STR }, PROP_POS_RANGE },
00209   { "Roff", PROP_REAL, { 1e12, PROP_NO_STR }, PROP_POS_RANGE },
00210   { "Temp", PROP_REAL, { 26.85, PROP_NO_STR }, PROP_MIN_VAL (K) },
00211   { "MaxDuration", PROP_REAL, { 1e-6, PROP_NO_STR }, PROP_MIN_VAL (10*NR_TINY) },
00212   { "Transition", PROP_STR, { PROP_NO_VAL, "spline" }, PROP_RNG_STR3 ("abrupt", "linear", "spline") },
00213   PROP_NO_PROP };
00214 struct define_t tswitch::cirdef =
00215   { "Switch", 2, PROP_COMPONENT, PROP_NO_SUBSTRATE, PROP_LINEAR, PROP_DEF };