...

Source file src/golang.conradwood.net/go-easyops/utils/interpolator.go

Documentation: golang.conradwood.net/go-easyops/utils

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"sync"
     7  )
     8  
     9  /*
    10  	given some reference points will interpolate a value,
    11  
    12  examples:
    13   1. reference points 5(50) and 10(100), interpolation: 7=70, 8=80,3=30 (0 is assumed), 11=100 (highest=max)
    14  */
    15  type Interpolator struct {
    16  	sync.Mutex
    17  	referencepoints []*interpolator_referencepoint
    18  }
    19  
    20  type interpolator_referencepoint struct {
    21  	number float64
    22  	value  float64
    23  }
    24  
    25  func (ip *Interpolator) AddReferencePoints(points map[float64]float64) {
    26  	for k, v := range points {
    27  		ip.AddReferencePoint(k, v)
    28  	}
    29  }
    30  func (ip *Interpolator) AddReferencePoint(number, value float64) {
    31  	ip.Lock()
    32  	defer ip.Unlock()
    33  	if len(ip.referencepoints) == 0 && number != 0 {
    34  		ip.referencepoints = append(ip.referencepoints, &interpolator_referencepoint{number: 0, value: 0})
    35  	}
    36  
    37  	// remove any that have same number
    38  	var res []*interpolator_referencepoint
    39  	for _, rp := range ip.referencepoints {
    40  		if rp.number == number {
    41  			continue
    42  		}
    43  		res = append(res, rp)
    44  	}
    45  	ip.referencepoints = res
    46  
    47  	// now append new number to it
    48  	ip.referencepoints = append(ip.referencepoints, &interpolator_referencepoint{number: number, value: value})
    49  
    50  	// and sort
    51  	sort.Slice(ip.referencepoints, func(i, j int) bool {
    52  		return ip.referencepoints[i].number < ip.referencepoints[j].number
    53  	})
    54  	var last *interpolator_referencepoint
    55  
    56  	// sanity check if ordering is ok
    57  	for _, ir := range ip.referencepoints {
    58  		if last == nil {
    59  			last = ir
    60  			continue
    61  		}
    62  		if ir.value < last.value {
    63  			fmt.Printf("WARNING: interpolator values out of order: %s\n", ip.String())
    64  		}
    65  		last = ir
    66  	}
    67  }
    68  
    69  /*
    70  fast and quick interpolation using linear interpolation
    71  */
    72  func (ip *Interpolator) LinearInterpolate(number float64) float64 {
    73  	ir1, ir2 := ip.findReferences(number)
    74  	if ir2 == nil {
    75  		// max out
    76  		//	fmt.Printf("Value %0.1f is maxed out, because highest is %s\n", number, ir1.String())
    77  		return ir1.value
    78  	}
    79  	xa := ir1.number
    80  	ya := ir1.value
    81  	xb := ir2.number
    82  	yb := ir2.value
    83  	x := number
    84  	diff := (x - xa) / (xb - xa)
    85  	y := ya + (yb-ya)*diff
    86  	//fmt.Printf("Value %0.1f is between %s and %s, diff=%0.1f, res=%0.1f\n", number, ir1.String(), ir2.String(), diff, y)
    87  	return y
    88  }
    89  func (ip *Interpolator) findReferences(number float64) (*interpolator_referencepoint, *interpolator_referencepoint) {
    90  	var ir1 *interpolator_referencepoint
    91  	var ir2 *interpolator_referencepoint
    92  	for i, ir := range ip.referencepoints {
    93  		if number < ir.number {
    94  			continue
    95  		}
    96  		ir1 = ir
    97  		if i < len(ip.referencepoints)-1 {
    98  			ir2 = ip.referencepoints[i+1]
    99  		} else {
   100  			ir2 = nil
   101  		}
   102  	}
   103  	return ir1, ir2
   104  }
   105  func (ip *Interpolator) String() string {
   106  	deli := ""
   107  	s := ""
   108  	for _, ir := range ip.referencepoints {
   109  		s = s + deli + fmt.Sprintf("%f->%f", ir.number, ir.value)
   110  		deli = ", "
   111  	}
   112  	return s
   113  }
   114  
   115  func (ir *interpolator_referencepoint) String() string {
   116  	return fmt.Sprintf("%f->%f", ir.number, ir.value)
   117  }
   118  

View as plain text