Qucs-core
0.0.19
|
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 };