Qucs-core
0.0.19
|
00001 /* 00002 * history.cpp - history class implementation 00003 * 00004 * Copyright (C) 2006, 2007 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 00025 #if HAVE_CONFIG_H 00026 # include <config.h> 00027 #endif 00028 00029 #include <stdio.h> 00030 #include <stdlib.h> 00031 #include <string.h> 00032 #include <cmath> 00033 00034 #include "precision.h" 00035 #include "tvector.h" 00036 #include "poly.h" 00037 #include "spline.h" 00038 #include "history.h" 00039 00040 namespace qucs { 00041 00042 00043 /* This function drops those values in the history which are newer 00044 than the specified time. */ 00045 void history::truncate (const nr_double_t tcut) 00046 { 00047 std::size_t i; 00048 std::size_t ts = this->t->size (); 00049 00050 for (i = this->leftidx (); i < ts; i++) 00051 { 00052 if ( (*this->t)[i] > tcut) 00053 { 00054 break; 00055 } 00056 } 00057 this->resize (ts - i); 00058 } 00059 00060 00061 /* This function drops those values in the history which are older 00062 than the specified age of the history instance. */ 00063 void history::drop (void) { 00064 if(this->values->empty()) 00065 return; 00066 nr_double_t f = this->first (); 00067 nr_double_t l = this->last (); 00068 if (age > 0.0 && l - f > age) { 00069 std::size_t r; 00070 std::size_t i = this->leftidx (); 00071 for (r = 0; i < this->t->size (); r++, i++) 00072 if (l - (*this->t)[i] < age) 00073 break; 00074 // keep 2 values being older than specified age 00075 r += this->unused (); 00076 if (r >= 2) 00077 r -= 2; 00078 r = std::min(r,this->values->size()-1); 00079 if (r > 127) 00080 /* erase the first r value */ 00081 this->values->erase(this->values->begin(),this->values->begin()+r); 00082 } 00083 } 00084 00085 /* Interpolates a value using 2 left side and 2 right side values if 00086 possible. */ 00087 nr_double_t history::interpol (nr_double_t tval, int idx, bool left) { 00088 static spline spl (SPLINE_BC_NATURAL); 00089 static tvector<nr_double_t> x (4); 00090 static tvector<nr_double_t> y (4); 00091 00092 unsigned int n = left ? idx + 1: idx; 00093 if (n > 1 && n + 2 < this->values->size ()) { 00094 int i, k, l = this->leftidx (); 00095 for (k = 0, i = n - 2; k < 4; i++, k++) { 00096 x (k) = (*this->t)[i + l]; 00097 y (k) = (*this->values)[i]; 00098 } 00099 spl.vectors (y, x); 00100 spl.construct (); 00101 return spl.evaluate (tval).f0; 00102 } 00103 return (*this->values)[idx]; 00104 } 00105 00106 /* The function returns the value nearest to the given time value. If 00107 the otional parameter is true then additionally cubic spline 00108 interpolation is used. */ 00109 nr_double_t history::nearest (nr_double_t tval, bool interpolate) { 00110 if (t->empty()) 00111 return 0.0; 00112 00113 int l = this->leftidx (); 00114 int r = t->size () - 1; 00115 int i = -1; 00116 nr_double_t diff = std::numeric_limits<nr_double_t>::max(); 00117 sign = true; 00118 i = seek (tval, l, r, diff, i); 00119 i = i - l; 00120 if (interpolate) 00121 return interpol (tval, i, sign); 00122 return (*this->values)[i]; 00123 } 00124 00125 /* The function is utilized in order to find the nearest value to a 00126 given time value. Since the time vector is ordered a recursive 00127 lookup algorithm can be used. The function returns the current 00128 index into the time vector as well as the error in time. */ 00129 int history::seek (nr_double_t tval, int l, int r, nr_double_t& diff, 00130 int idx) { 00131 int i = (l + r) / 2; 00132 if (l == r) 00133 return i; 00134 nr_double_t v = (*this->t)[i]; 00135 nr_double_t d = v - tval; 00136 if (fabs (d) < diff) { 00137 // better approximation 00138 diff = fabs (d); 00139 sign = d < 0.0 ? true : false; 00140 idx = i; 00141 } 00142 else if (i == l) { 00143 // no better 00144 return idx; 00145 } 00146 if (d < 0.0) { 00147 // look later 00148 return seek (tval, i, r, diff, idx); 00149 } 00150 else if (d > 0.0) { 00151 // look earlier 00152 return seek (tval, l, i, diff, idx); 00153 } 00154 return idx; 00155 } 00156 00157 } // namespace qucs