github.com/go-graphite/carbonapi@v0.17.0/expr/functions/ifft/function.go (about)

     1  package ifft
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  	"math/cmplx"
     7  
     8  	"github.com/go-graphite/carbonapi/expr/helper"
     9  	"github.com/go-graphite/carbonapi/expr/interfaces"
    10  	"github.com/go-graphite/carbonapi/expr/types"
    11  	"github.com/go-graphite/carbonapi/pkg/parser"
    12  	realFFT "github.com/mjibson/go-dsp/fft"
    13  )
    14  
    15  type ifft struct{}
    16  
    17  func GetOrder() interfaces.Order {
    18  	return interfaces.Any
    19  }
    20  
    21  func New(configFile string) []interfaces.FunctionMetadata {
    22  	res := make([]interfaces.FunctionMetadata, 0)
    23  	f := &ifft{}
    24  	functions := []string{"ifft"}
    25  	for _, n := range functions {
    26  		res = append(res, interfaces.FunctionMetadata{Name: n, F: f})
    27  	}
    28  	return res
    29  }
    30  
    31  // ifft(absSeriesList, phaseSeriesList)
    32  func (f *ifft) Do(ctx context.Context, eval interfaces.Evaluator, e parser.Expr, from, until int64, values map[parser.MetricRequest][]*types.MetricData) ([]*types.MetricData, error) {
    33  	absSeriesList, err := helper.GetSeriesArg(ctx, eval, e.Arg(0), from, until, values)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	var phaseSeriesList []*types.MetricData
    39  	if e.ArgsLen() > 1 {
    40  		phaseSeriesList, err = helper.GetSeriesArg(ctx, eval, e.Arg(1), from, until, values)
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  	}
    45  
    46  	results := make([]*types.MetricData, len(absSeriesList))
    47  	for j, a := range absSeriesList {
    48  		r := a.CopyLinkTags()
    49  		r.Values = make([]float64, len(a.Values))
    50  		if len(phaseSeriesList) > j {
    51  			p := phaseSeriesList[j]
    52  			r.Name = "ifft(" + a.Name + "," + p.Name + ")"
    53  			values := make([]complex128, len(a.Values))
    54  			for i, v := range a.Values {
    55  				if math.IsNaN(v) {
    56  					v = 0
    57  				}
    58  
    59  				values[i] = cmplx.Rect(v, p.Values[i])
    60  			}
    61  
    62  			values = realFFT.IFFT(values)
    63  			for i, v := range values {
    64  				r.Values[i] = cmplx.Abs(v)
    65  			}
    66  		} else {
    67  			r.Name = "ifft(" + a.Name + ")"
    68  			values := realFFT.IFFTReal(a.Values)
    69  			for i, v := range values {
    70  				r.Values[i] = cmplx.Abs(v)
    71  			}
    72  		}
    73  
    74  		results[j] = r
    75  	}
    76  	return results, nil
    77  }
    78  
    79  // Description is auto-generated description, based on output of https://github.com/graphite-project/graphite-web
    80  func (f *ifft) Description() map[string]types.FunctionDescription {
    81  	return map[string]types.FunctionDescription{
    82  		"ifft": {
    83  			Description: "An algorithm that samples a signal over a period of time (or space) and divides it into its frequency components. Computes discrete Fourier transform https://en.wikipedia.org/wiki/Fast_Fourier_transform \n\nExample:\n\n.. code-block:: none\n\n  &target=fft(server*.requests_per_second)\n\n  &target=fft(server*.requests_per_second, \"abs\")\n",
    84  			Function:    "ifft(seriesList, phaseSeriesList)",
    85  			Group:       "Transform",
    86  			Module:      "graphite.render.functions.custom",
    87  			Name:        "ifft",
    88  			Params: []types.FunctionParam{
    89  				{
    90  					Name:     "seriesList",
    91  					Required: true,
    92  					Type:     types.SeriesList,
    93  				},
    94  				{
    95  					Name:     "phaseSeriesList",
    96  					Required: true,
    97  					Type:     types.SeriesList,
    98  				},
    99  			},
   100  			NameChange:   true, // name changed
   101  			ValuesChange: true, // values changed
   102  		},
   103  	}
   104  }