2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 *------------------------------------------------------------------
22 * "wave" class, for transmission lines and delays
24 //testing=script 2006.07.13
25 #include "l_denoise.h"
28 #include <boost/range/iterator_range.hpp>
29 /*--------------------------------------------------------------------------*/
35 typedef std::deque
<DPAIR
>::iterator iterator
;
36 typedef std::deque
<DPAIR
>::const_iterator const_iterator
;
38 explicit WAVE(double d
=0);
39 explicit WAVE(const WAVE
&);
41 WAVE
& set_delay(double d
);
43 WAVE
& push(double t
, double v
);
44 FPOLY1
v_out(double t
)const;
45 FPOLY1
operator()(double xx
)const {return v_out(xx
);}
46 double v_reflect(double t
, double v_total
)const;
47 WAVE
& operator+=(const WAVE
& x
);
48 WAVE
& operator+=(double x
);
49 WAVE
& operator*=(const WAVE
& x
);
50 WAVE
& operator*=(double x
);
52 double dhd_linear(const WAVE
& x
, std::pair
<DPAIR
, DPAIR
>* where
=NULL
) const;
53 double dhd_discrete(const WAVE
& x
, std::pair
<DPAIR
, DPAIR
>* where
=NULL
) const;
54 const_iterator
begin()const {return _w
.begin();}
55 const_iterator
end()const {return _w
.end();}
56 size_t size()const {return _w
.size();}
59 double segment2point(const_iterator l
, const DPAIR
& p
, DPAIR
* where
=NULL
) const;
60 double norm2(const DPAIR
&, const DPAIR
&) const;
61 double norm2(const DPAIR
&) const;
62 double point2chain(DPAIR p
, const_iterator B
, DPAIR
* w
=NULL
) const; // FIXME: pass right end
63 double edge2chain(DPAIR l
, DPAIR r
, const_iterator
& L
, const_iterator
& R
, std::pair
<DPAIR
, DPAIR
>* where
=NULL
) const;
64 FPOLY1
bisector_dual(const const_iterator
& a
, const const_iterator
& b
) const;
65 double bisector_distance(const const_iterator
& a
, const const_iterator
& b
, DPAIR l
, DPAIR r
) const;
66 double endpoints2chain(DPAIR l
, DPAIR r
, const_iterator
& L
, const_iterator
& R
, std::pair
<DPAIR
, DPAIR
>* where
=NULL
) const;
73 RANGE(const const_iterator
& a
, const const_iterator
& b
) : _a(a
), _b(b
){ untested();}
74 const_iterator
begin() const {return _a
;}
75 const_iterator
end() const {return _b
;}
78 /*--------------------------------------------------------------------------*/
79 /*--------------------------------------------------------------------------*/
80 // push: insert a signal on the "input" end.
81 // args: t = the time now
82 // v = the value to push
84 inline WAVE
& WAVE::push(double t
, double v
)
86 _w
.push_back(DPAIR(t
+_delay
, v
));
89 /*--------------------------------------------------------------------------*/
90 // initialize: remove all info, fill it with all 0.
92 inline WAVE
& WAVE::initialize()
97 /*--------------------------------------------------------------------------*/
98 inline WAVE::WAVE(const WAVE
& w
)
103 /*--------------------------------------------------------------------------*/
104 // constructor -- argument is the delay
106 inline WAVE::WAVE(double d
)
112 /*--------------------------------------------------------------------------*/
113 inline WAVE
& WAVE::set_delay(double d
)
118 /*--------------------------------------------------------------------------*/
119 // v_out: return the value at the "output" end
120 // args: t = the time now
122 inline FPOLY1
WAVE::v_out(double t
)const
124 return interpolate(_w
.begin(), _w
.end(), t
, 0., 0.);
126 /*--------------------------------------------------------------------------*/
127 // reflect: calculate a reflection
128 // args: t = the time now
129 // v_total = actual voltage across the termination
130 // returns: the value (voltage) to send back as the reflection
132 inline double WAVE::v_reflect(double t
, double v_total
)const
134 // return (v_total*2 - v_out(t)); // de-noised
135 return dn_diff(v_total
*2, v_out(t
).f0
);
137 /*--------------------------------------------------------------------------*/
138 inline WAVE
& WAVE::operator+=(const WAVE
& x
)
141 for (std::deque
<DPAIR
>::iterator
142 i
= _w
.begin(); i
!= _w
.end(); ++i
) {
144 (*i
).second
+= x
.v_out((*i
).first
).f0
;
148 /*--------------------------------------------------------------------------*/
149 inline WAVE
& WAVE::operator+=(double x
)
152 for (std::deque
<DPAIR
>::iterator
153 i
= _w
.begin(); i
!= _w
.end(); ++i
) {
159 /*--------------------------------------------------------------------------*/
160 inline WAVE
& WAVE::operator*=(const WAVE
& x
)
163 for (std::deque
<DPAIR
>::iterator
164 i
= _w
.begin(); i
!= _w
.end(); ++i
) {
166 (*i
).second
*= x
.v_out((*i
).first
).f0
;
170 /*--------------------------------------------------------------------------*/
171 inline WAVE
& WAVE::operator*=(double x
)
173 for (std::deque
<DPAIR
>::iterator
174 i
= _w
.begin(); i
!= _w
.end(); ++i
) {
179 /*--------------------------------------------------------------------------*/
180 inline WAVE
& WAVE::warp(double t
)
183 for (std::deque
<DPAIR
>::iterator
184 i
= _w
.begin(); i
!= _w
.end(); ++i
) {
189 /*--------------------------------------------------------------------------*/
190 inline double WAVE::norm2(const DPAIR
& a
) const
192 double sum
= (a
.first
) * (a
.first
);
193 assert(is_number(sum
));
194 sum
+= (a
.second
) * (a
.second
);
195 assert(is_number(sum
));
198 /*--------------------------------------------------------------------------*/
199 inline double WAVE::norm2(const DPAIR
& a
, const DPAIR
& b
) const
201 double sum
= (a
.first
- b
.first
) * (a
.first
- b
.first
);
202 assert(is_number(sum
));
203 sum
+= (a
.second
- b
.second
) * (a
.second
- b
.second
);
204 assert(is_number(sum
));
207 /*--------------------------------------------------------------------------*/
208 inline DPAIR
operator+(const DPAIR
& a
, const DPAIR
& b
)
211 sum
.first
+= b
.first
;
212 sum
.second
+= b
.second
;
215 /*--------------------------------------------------------------------------*/
216 inline DPAIR
operator-(const DPAIR
& a
, const DPAIR
& b
)
219 sub
.first
-= b
.first
;
220 sub
.second
-= b
.second
;
223 /*--------------------------------------------------------------------------*/
224 inline DPAIR
operator*(const double& t
, const DPAIR
& a
)
231 #if __cplusplus > 199711L
232 // compute segment to point distance
233 // take left endpoint of segment
234 inline double WAVE::segment2point(const_iterator li
, const DPAIR
& p
, DPAIR
* where
) const
236 WAVE::const_iterator ri
= next(li
);
239 // trace3("norm2", l, r, p);
242 if(li
== end()){ unreachable();
243 }else if(ri
== end()){
250 if(l
.first
>= r
.first
){
251 error(bDANGER
, "something wrong %E %E\n", l
.first
, r
.first
);
253 assert(l
.first
< r
.first
);
254 // solve l + t*(r-l) closest to p
257 double p2
= p
.second
;
259 double l2
= l
.second
;
261 double r2
= r
.second
;
262 t
= - (p1
- l1
) * (l1
- r1
) - (p2
- l2
) * (l2
- r2
);
263 assert(is_number(t
));
264 t
/= (l1
- r1
) * (l1
- r1
) + (l2
- r2
) * (l2
- r2
);
265 assert(is_number(t
));
279 // trace2("norm2 found", t, ret);
283 /*--------------------------------------------------------------------------*/
284 // compute directed distance from point to chain
285 // distance is min_{x \in chain} |b-x|
286 // chain is iterator of this starting at B
287 // edge has vertices l and r
288 // FIXME: pass right end.
289 inline double WAVE::point2chain(DPAIR p
, const_iterator L
, DPAIR
* w
) const
293 double ret
= norm2(*L
,p
);
296 trace2("point2chain", ret
, *w
);
299 while(next(L
) != end() && L
->first
< p
.first
+ret
){
300 trace2("point2chain", *L
, *next(L
));
301 assert(next(L
)!=end());
303 DPAIR
* pw2
= (w
)? &w2
: NULL
;
304 double distance
= segment2point(L
,p
,pw2
);
305 trace4("point2chain", p
, distance
, *L
, w2
);
315 trace4("point2chain", p
, *L
, *next(L
), ret
);
316 if(w
) trace1("point2chain", *w
);
319 /*--------------------------------------------------------------------------*/
320 // compute bisector of 2 edges
321 inline FPOLY1
WAVE::bisector_dual(const const_iterator
& a
, const const_iterator
& b
) const
324 FPOLY1
fa(a
->first
, a
->second
, (next(a
)->second
- a
->second
)/(next(a
)->first
- a
->first
));
325 FPOLY1
fb(b
->first
, b
->second
, (next(b
)->second
- b
->second
)/(next(b
)->first
- b
->first
));
327 // trace2("bisector_dual", *a, *next(a));
328 // trace2("bisector_dual", *b, *next(b));
329 // trace2("bisector_dual", fa, fb);
330 // trace2("bisector_dual", CPOLY1(fa), CPOLY1(fb));
332 DPAIR t
= CPOLY1(fa
).intersect(CPOLY1(fb
));
333 // trace1("bisector_dual", t);
335 double norma
= 1./norm2(*next(a
) - *a
);
336 DPAIR A
= norma
*(*next(a
) - *a
);
337 double normb
= 1./norm2(*next(b
) - *b
);
338 DPAIR B
= normb
*(*next(b
) - *b
);
341 return FPOLY1(t
.first
, t
.second
, sum
.second
/sum
.first
);
343 /*--------------------------------------------------------------------------*/
344 // find distance from endpoints to chain
345 // update chain iterators to relevant region for inner points
346 inline double WAVE::endpoints2chain(DPAIR l
, DPAIR r
, const_iterator
& L
, const_iterator
& R
, std::pair
<DPAIR
, DPAIR
>* where
) const
348 trace4("endpoints2chain start....", l
, r
, *L
, *R
);
352 assert(R
!= end()); // bad right end.
353 auto Lsave
= L
; // mark start, so we don't sweep twice
355 auto Lmin
= L
; // found minimal distance here (points to left vertex of edge)
356 DPAIR hmmmL
, hmmmR
; // FIXME: merge. later.
357 DPAIR
* hmmmLp
= NULL
;
358 DPAIR
* hmmmRp
= NULL
;
365 double distL
= norm2(*L
, l
);
368 // shift L to left if necessary
370 double tmp
= segment2point(prev(L
), l
, hmmmLp
);
371 if(tmp
< distL
){ untested();
373 if(where
){ untested();
374 where
->second
= hmmmL
;
378 } else if( prev(L
)->first
> l
.first
- distL
) {
385 trace4("endpoints2chain first L pass", *Lsave
, *Lmin
, distL
, hmmmL
);
386 // shift L to the right as much as possible
387 while(next(Lsave
)!=end()){
388 trace3("L ->", *Lsave
, *next(Lsave
), *R
);
389 double tmp
= segment2point(Lsave
, l
, hmmmLp
);
393 where
->second
= hmmmL
;
397 } else if( Lsave
->first
< l
.first
+ distL
) {
404 trace4("endpoints2chain second L pass", *Lsave
, *Lmin
, distL
, hmmmL
);
407 double distR
= norm2(*R
, r
);
413 auto Rmin
= R
; // found minimal distance here (points to right vertex of edge)
415 trace2("guess", distR
, *R
);
416 // shift R to right if neccessary
417 while(next(R
)!=end()){
418 trace3("R ->", *R
, r
, *prev(R
));
419 double tmp
= segment2point(R
, r
, hmmmRp
); // check edge right to range
422 if(where
&& (distR
> distL
)){
423 trace1("endpoints2chain R->", hmmmR
);
424 where
->second
= hmmmR
;
426 trace3("endpoints2chain R-> nosecond", hmmmR
, distL
, distR
);
430 } else if( R
->first
< r
.first
+ distR
) {
437 trace6("endpoints2chain done first R pass", *Rsave
, *Rmin
, *next(Rmin
), distR
, *R
, hmmmR
);
440 // shift R to the left as much as possible
441 while(Rsave
!= Lmin
){
442 assert(Rsave
!=begin());
443 double tmp
= segment2point(prev(Rsave
), r
, hmmmRp
);
448 if(where
&& (distR
> distL
)){
449 trace1("endpoints2chain <-R", hmmmR
);
450 where
->second
= hmmmR
;
452 trace3("endpoints2chain <-R nosecond", hmmmR
, distL
, distR
);
454 } else if( prev(Rsave
)->first
< r
.first
+ distR
) {
460 trace6("endpoints2chain done second R pass", *Rsave
, *Rmin
, *next(Rmin
), distR
, *R
, hmmmR
);
464 trace4("endpoints2chain check", *L
, *R
, distL
, distR
);
465 assert(L
->first
<= R
->first
);
474 trace8("endpoints2chain done", l
, r
, *Lmin
, *Rmin
, distL
, distR
, *L
, *R
);
478 //where->second = hmmmL;
479 trace1("endpoints2chain done l", where
->second
);
485 trace1("endpoints2chain done r", where
->second
);
486 //where->second = hmmmR;
491 /*--------------------------------------------------------------------------*/
492 // compute worst case distance from edge to chain, leaving out right (?) endpoint
493 // chain is subsegment of this incluging L .. R
494 // edge has vertices l and r
495 // B will be incremented as needed
496 inline double WAVE::edge2chain(DPAIR l
, DPAIR r
, const_iterator
& L
, const_iterator
& R
, std::pair
<DPAIR
, DPAIR
>* where
) const
499 trace4("edge2chain...", l
, r
, *L
, *R
);
501 // need to check (left) endpoint of edge against range
502 if(l
== r
){ incomplete();
503 return point2chain(l
,L
);
506 ret
= endpoints2chain(l
, r
, L
, R
, where
);
507 trace5("edge2chain new endpoints", l
, r
, *L
, *R
, ret
);
508 if (where
) trace2("", where
->first
, where
->second
);
510 std::set
<DPAIR
> intersections
;
512 for(auto a
= L
; a
!= R
; ++a
){
513 trace2("iterating left...", *a
, *next(a
));
516 for(auto b
= next(a
); b
!= R
; ++b
){
517 assert (next(b
)!=end());
518 trace2("iterating right...", *b
, *next(b
));
520 if (b
==end()){ incomplete();
522 } else if (next(b
)==end()){ incomplete();
523 // we have only one edge left
526 // need to check bisector
528 FPOLY1 bis
= bisector_dual(a
,b
); // cache?
529 trace5("bisector...", *a
, *next(a
), *b
, *next(b
), bis
);
532 double t
= CPOLY1(edge
).zero(bis
);
534 if(t
>=l
.first
&& t
<=r
.first
){
536 trace6("found intersection...", t
, ft
, *a
, *b
, l
, r
);
538 DPAIR
* w2
= (where
)? &ww
: NULL
;
539 double d
= point2chain(DPAIR(t
,ft
), a
, w2
); // FIXME. pass right end
540 if(w2
) trace1("point2chain done", *w2
);
542 trace1("intersection is closer", d
);
545 trace2("further intersection...", *w2
, d
);
546 where
->first
= DPAIR(t
,ft
);
552 trace3("no intersection", t
, bis
, edge
);
560 /*--------------------------------------------------------------------------*/
561 // compute directed hausdorff distance from this to that using linear
563 // == max_{i \in lin(this)} min_{j \in lin(that)} d(i,j)
564 inline double WAVE::dhd_linear(const WAVE
& that
, std::pair
<DPAIR
,DPAIR
>* wp
) const
566 auto L
= that
.begin();
568 assert(L
!=that
.end()); // for now.
570 double ret
= 0.; // fabs(that.v_out(begin()->first).f0 - begin()->second);
572 for(auto ii
= begin(); ; ++ii
){
573 auto other
= next(ii
);
575 // ret = std::max(ret, fabs(other->second - that.v_out(other->first).f0)); // hmmm
576 trace3("dhd outer loop", ret
, *ii
, *other
);
580 trace3("dhd, end", *ii
, ret
, *L
);
582 auto wp2
= (wp
)? &ww
: NULL
;
583 double r
= that
.point2chain(*ii
, L
, wp2
);
592 trace3("dhd end", ii
->first
, ret
, *L
);
593 if(wp
) trace3("dhd end", ii
->second
, wp
->first
, wp
->second
);
595 } else if (R
==that
.end()) { untested();
597 auto wp2
= (wp
)? &ww
: NULL
;
598 double r
= that
.segment2point(ii
, *L
, wp2
);
599 if(ret
<r
){untested();
606 trace3("dhd singleton chain", ret
, *L
, *R
);
608 // perform windowed sweep.
609 std::pair
<DPAIR
,DPAIR
> ww
;
610 auto wp2
= (wp
)? &ww
: NULL
;
611 double r
= that
.edge2chain(*ii
, *other
, L
, R
, wp2
);
618 trace5("dhd windowed sweep, found", *ii
, *other
, ret
, *L
, *R
);
619 if(wp
) trace3("dhd windowed sweep", ret
, wp
->first
, wp
->second
);
628 /*--------------------------------------------------------------------------*/
629 // compute directed hausdorff distance from points of this to points of that
630 // this is useless, so lets not try to be efficient.
631 inline double WAVE::dhd_discrete(const WAVE
& that
, std::pair
<DPAIR
, DPAIR
>* where
) const
637 for(auto j
: that
._w
) {
638 double norm
= norm2(ii
,j
);
650 where
->second
= here
;
657 /*--------------------------------------------------------------------------*/
658 // vim:ts=8:sw=2:noet: