// DCT returns DCT-II coefficients given an input signal. func DCT(x []float64) []float64 { n := len(x) nh := n / 2 evenVector := make([]float64, n) for i := 0; i < nh; i++ { evenVector[i], evenVector[n-1-i] = x[2*i], x[2*i+1] } array := fft.FFTReal(evenVector) theta := math.Pi / (2.0 * float64(n)) // 1/4 Shift for k := 1; k < nh; k++ { w := cmplx.Exp(complex(0, -float64(k)*theta)) wCont := -complex(imag(w), real(w)) array[k] *= w array[n-k] *= wCont } array[nh] *= complex(math.Cos(theta*float64(nh)), 0.0) dctCoef := make([]float64, n) for i := range dctCoef { dctCoef[i] = real(array[i]) } return dctCoef }
// Compute the spectrogram of a signal with window width nfft and overlap // percentage overlap. func Compute(signal []float64, nfft int, overlap float64) Spectrogram { spectra := make([][]complex128, 0) start := 0 end := start + nfft off := int((1 - overlap) * float64(nfft)) // pre-compute the window function window := window.Hamming(nfft) // pre-allocate buffer to hold window * signal windowed := make([]float64, nfft) for end < len(signal) { for i, s := range signal[start:end] { windowed[i] = s * window[i] } spectrum := fft.FFTReal(windowed) // FIXME: memory is still used for the entire spectrum since the GC doesn't // understand and can't free internal and partial pointers, to free it must // do a copy. If this spectrum persists for a while then we should do a // copy(). spectra = append(spectra, spectrum[0:len(spectrum)/2]) start += off end += off } spectrogram := Spectrogram{spectra, nil} return spectrogram }
func SamplesToFrequencies(samples *TMSnippet) Frequencies { var freqs Frequencies f64samples := make([]float64, len(samples.Samples)) for i, v := range samples.Samples { f64samples[i] = float64(v) } freqs.Freqs = cplxsToReals(fft.FFTReal(f64samples)) freqs.DeltaHz = 1 / samples.SampleHz // TODO: check if this even makes sense return freqs }
func buildFFT(data tsData) [][]float64 { x := make([]float64, len(data.Values)) for i, d := range data.Values { x[i] = d.Value } X := fft.FFTReal(x) Xout := make([][]float64, len(X)) for i, Xi := range X { Xout[i] = make([]float64, 2) Xout[i][0] = real(Xi) Xout[i][1] = imag(Xi) } return Xout }
// NewSpectrogram constructs a spectrogram // windowLen should be a power of 2 func NewSpectrogram(r io.Reader, windowLen, overlap int) (*Spectrogram, error) { data, err := wav.ReadWav(r) if err != nil { return &Spectrogram{}, err } if expected, actual := uint16(16), data.BitsPerSample; expected != actual { return &Spectrogram{}, fmt.Errorf("rate %d, not %d", actual, expected) } if expected, actual := uint16(1), data.NumChannels; expected != actual { return &Spectrogram{}, fmt.Errorf("%d chans, not %d", actual, expected) } // find maximum energy max := -math.MaxFloat64 for _, value := range data.Data { if max < float64(value[0]) { max = float64(value[0]) } } sampleData := make([]float64, data.NumSamples) for i := range data.Data { sampleData[i] = float64(data.Data[i][0]) / max } // create hammed windows for the fft windows := spectral.Segment(sampleData, windowLen, overlap) nWindow := len(windows) // (len(sampleData) - windowLen) / (windowLen - overlap) + 1 ApplyHamming(windows) // do the fft, get positive fq components, and discard phase s := Spectrogram{ data: make([][]float64, nWindow), sampleRate: data.SampleRate, windowLength: windowLen, overlap: overlap, numSamples: data.NumSamples, } for i, w := range windows { s.data[i] = make([]float64, int(windowLen/2)) for j, v := range fft.FFTReal(w)[0:int(windowLen/2)] { s.data[i][j] = 2 * cmplx.Abs(v) } } return &s, nil }
// STFT returns complex spectrogram given an input signal. func (s *STFT) STFT(input []float64) [][]complex128 { numFrames := s.NumFrames(input) spectrogram := make([][]complex128, numFrames) frames := s.DivideFrames(input) for i, frame := range frames { // Windowing windowed := window.Windowing(frame, s.Window) // Complex Spectrum spectrogram[i] = fft.FFTReal(windowed) } return spectrogram }
func (cq *ConstantQ) processOctaveBlock(octave int) [][]complex128 { apf := cq.kernel.Properties.atomsPerFrame bpo := cq.kernel.Properties.binsPerOctave fftHop := cq.kernel.Properties.fftHop fftSize := cq.kernel.Properties.fftSize cv := fft.FFTReal(cq.buffers[octave][:fftSize]) cq.buffers[octave] = cq.buffers[octave][fftHop:] cqrowvec := cq.kernel.processForward(cv) // Reform into a column matrix cqblock := make([][]complex128, apf, apf) for j := 0; j < apf; j++ { cqblock[j] = make([]complex128, bpo, bpo) for i := 0; i < bpo; i++ { cqblock[j][i] = cqrowvec[i*apf+j] } } return cqblock }
func fftanalyzer(values chan []int32) { for { in := <-values var buf [2048]float64 for k := 0; k <= (len(in)/2)-2; k++ { v1 := float64(in[k*2]) * 0.5 * (1.0 - math.Cos(2.0*math.Pi*float64(k*2)/(float64(len(in))-1.0))) v2 := float64(in[k*2+1]) * 0.5 * (1.0 - math.Cos(2.0*math.Pi*float64(k*2)/(float64(len(in))-1.0))) buf[k] = v1 + v2 } buffer := fft.FFTReal(buf[0:2048]) for i, val := range buffer { buf[i] = cmplx.Abs(val) } var sendBuf [64]float64 sendBuf[0] = fftAvg(buf[0:len(buf)-1], 0, 30) sendBuf[1] = fftAvg(buf[0:len(buf)-1], 31, 60) sendBuf[2] = fftAvg(buf[0:len(buf)-1], 61, 100) sendBuf[3] = fftAvg(buf[0:len(buf)-1], 101, 150) sendBuf[4] = fftAvg(buf[0:len(buf)-1], 151, 200) sendBuf[5] = fftAvg(buf[0:len(buf)-1], 201, 250) sendBuf[6] = fftAvg(buf[0:len(buf)-1], 251, 300) sendBuf[7] = fftAvg(buf[0:len(buf)-1], 301, 350) sendBuf[8] = fftAvg(buf[0:len(buf)-1], 351, 400) for n := 9; n < 64; n++ { sendBuf[n] = fftAvg(buf[0:len(buf)-1], (351 + (250 * (n - 9))), (500 + (250 * (n - 9)))) } send := make([]int64, 64) x := 8.0 y := 3.0 for h, v := range sendBuf { q := v * (math.Log(x) / y) x = x + (x) send[h] = int64(q) / math.MaxInt32 } fft_values <- send } }
func KCMmeans(rawData [][]float64, k int, distanceFunction DistanceFunction, threshold int) ([]int, []Observation, error) { var minClusteredData []ClusteredObservation var means []Observation var err error max, trace := int64(0), make([]float64, k) for clusters := 1; clusters <= k; clusters++ { data := make([]ClusteredObservation, len(rawData)) for ii, jj := range rawData { data[ii].Observation = jj } seeds := seed(data, clusters, distanceFunction) clusteredData, _ := kmeans(data, seeds, distanceFunction, threshold) counts := make([]int, clusters) for _, jj := range clusteredData { counts[jj.ClusterNumber]++ } input := &bytes.Buffer{} for c := 0; c < clusters; c++ { /*err := binary.Write(input, binary.LittleEndian, rand.Float64()) if err != nil { panic(err) }*/ err := binary.Write(input, binary.LittleEndian, int64(counts[c])) if err != nil { panic(err) } for _, jj := range seeds[c] { err = binary.Write(input, binary.LittleEndian, jj) if err != nil { panic(err) } } for _, j := range clusteredData { if j.ClusterNumber == c { for ii, jj := range j.Observation { err = binary.Write(input, binary.LittleEndian, jj-seeds[c][ii]) if err != nil { panic(err) } } } } } in, output := make(chan []byte, 1), &bytes.Buffer{} in <- input.Bytes() close(in) compress.BijectiveBurrowsWheelerCoder(in).MoveToFrontRunLengthCoder().AdaptiveCoder().Code(output) /*output := &bytes.Buffer{} writer := lzma.NewWriterLevel(output, lzma.BestCompression) writer.Write(input.Bytes()) writer.Close()*/ complexity := int64(output.Len()) trace[clusters-1] = float64(complexity) fmt.Printf("%v %v\n", clusters, complexity) if complexity > max { max, minClusteredData, means = complexity, clusteredData, make([]Observation, len(seeds)) for ii := range seeds { means[ii] = make([]float64, len(seeds[ii])) for jj := range seeds[ii] { means[ii][jj] = seeds[ii][jj] } } } } f := fft.FFTReal(trace) points, phase, complex := make(plotter.XYs, len(f)-1), make(plotter.XYs, len(f)-1), make(plotter.XYs, len(f)) for i, j := range f[1:] { points[i].X, points[i].Y = float64(i), cmplx.Abs(j) phase[i].X, phase[i].Y = float64(i), cmplx.Phase(j) complex[i].X, complex[i].Y = real(j), imag(j) } p, err := plot.New() if err != nil { panic(err) } p.Title.Text = "FFT Real" p.X.Label.Text = "X" p.Y.Label.Text = "Y" scatter, err := plotter.NewScatter(points) if err != nil { panic(err) } scatter.Shape = draw.CircleGlyph{} scatter.Radius = vg.Points(1) p.Add(scatter) if err := p.Save(8, 8, "fft_real.png"); err != nil { panic(err) } p, err = plot.New() if err != nil { panic(err) } p.Title.Text = "FFT Phase" p.X.Label.Text = "X" p.Y.Label.Text = "Y" scatter, err = plotter.NewScatter(phase) if err != nil { panic(err) } scatter.Shape = draw.CircleGlyph{} scatter.Radius = vg.Points(1) scatter.Color = color.RGBA{0, 0, 255, 255} p.Add(scatter) if err := p.Save(8, 8, "fft_phase.png"); err != nil { panic(err) } p, err = plot.New() if err != nil { panic(err) } p.Title.Text = "FFT Complex" p.X.Label.Text = "X" p.Y.Label.Text = "Y" scatter, err = plotter.NewScatter(complex) if err != nil { panic(err) } scatter.Shape = draw.CircleGlyph{} scatter.Radius = vg.Points(1) scatter.Color = color.RGBA{0, 0, 255, 255} p.Add(scatter) if err := p.Save(8, 8, "fft_complex.png"); err != nil { panic(err) } labels := make([]int, len(minClusteredData)) for ii, jj := range minClusteredData { labels[ii] = jj.ClusterNumber } return labels, means, err }
// Pwelch estimates the power spectral density of x using Welch's method. // Fs is the sampling frequency (samples per time unit) of x. Fs is used // to calculate freqs. // Returns the power spectral density Pxx and corresponding frequencies freqs. // Designed to be similar to the matplotlib implementation below. // Reference: http://matplotlib.org/api/mlab_api.html#matplotlib.mlab.psd // See also: http://www.mathworks.com/help/signal/ref/pwelch.html func Pwelch(x []float64, Fs float64, o *PwelchOptions) (Pxx, freqs []float64) { if len(x) == 0 { return []float64{}, []float64{} } nfft := o.NFFT pad := o.Pad noverlap := o.Noverlap wf := o.Window enable_scaling := !o.Scale_off if nfft == 0 { nfft = 256 } if wf == nil { wf = window.Hann } if pad == 0 { pad = nfft } if len(x) < nfft { x = dsputils.ZeroPadF(x, nfft) } lp := pad/2 + 1 var scale float64 = 2 segs := Segment(x, nfft, noverlap) Pxx = make([]float64, lp) for _, x := range segs { x = dsputils.ZeroPadF(x, pad) window.Apply(x, wf) pgram := fft.FFTReal(x) for j := range Pxx { d := real(cmplx.Conj(pgram[j])*pgram[j]) / float64(len(segs)) if j > 0 && j < lp-1 { d *= scale } Pxx[j] += d } } w := wf(nfft) var norm float64 for _, x := range w { norm += math.Pow(x, 2) } if enable_scaling { norm *= Fs } for i := range Pxx { Pxx[i] /= norm } freqs = make([]float64, lp) coef := Fs / float64(pad) for i := range freqs { freqs[i] = float64(i) * coef } return }
// Run is the block's main loop. Here we listen on the different channels we set up. func (b *Timeseries) Run() { var err error //var path, lagStr string var path string var tree *jee.TokenTree //var lag time.Duration var data tsData var numSamples float64 // defaults numSamples = 1 for { select { case ruleI := <-b.inrule: // set a parameter of the block rule, ok := ruleI.(map[string]interface{}) if !ok { b.Error(errors.New("could not assert rule to map")) } path, err = util.ParseString(rule, "Path") if err != nil { b.Error(err) continue } tree, err = util.BuildTokenTree(path) if err != nil { b.Error(err) continue } /* lagStr, err = util.ParseString(rule, "Lag") if err != nil { b.Error(err) continue } lag, err = time.ParseDuration(lagStr) if err != nil { b.Error(err) continue } */ numSamples, err = util.ParseFloat(rule, "NumSamples") if err != nil { b.Error(err) continue } data = tsData{ Values: make([]tsDataPoint, int(numSamples)), } case <-b.quit: // quit * time.Second the block return case msg := <-b.in: if tree == nil { continue } if data.Values == nil { continue } // deal with inbound data v, err := jee.Eval(tree, msg) if err != nil { b.Error(err) continue } var val float64 switch v := v.(type) { case float32: val = float64(v) case int: val = float64(v) case float64: val = v } //t := float64(time.Now().Add(-lag).Unix()) t := float64(time.Now().Unix()) d := tsDataPoint{ Timestamp: t, Value: val, } data.Values = append(data.Values[1:], d) case respChan := <-b.queryrule: // deal with a query request respChan <- map[string]interface{}{ //"Window": lagStr, "Path": path, "NumSamples": numSamples, } case respChan := <-b.querystate: out := map[string]interface{}{ "timeseries": data, } respChan <- out case respChan := <-b.queryfft: x := make([]float64, len(data.Values)) for i, d := range data.Values { x[i] = d.Value } X := fft.FFTReal(x) Xout := make([][]float64, len(X)) for i, Xi := range X { Xout[i] = make([]float64, 2) Xout[i][0] = real(Xi) Xout[i][1] = imag(Xi) } out := map[string]interface{}{ "fft": Xout, } respChan <- out case <-b.inpoll: outArray := make([]interface{}, len(data.Values)) for i, d := range data.Values { di := map[string]interface{}{ "timestamp": d.Timestamp, "value": d.Value, } outArray[i] = di } out := map[string]interface{}{ "timeseries": outArray, } b.out <- out } } }
// Return the real and imaginary parts of the fft func (d *DataFrame) FFT() []complex128 { data := d.Data() return fft.FFTReal(data) }
// Cepstrum2Amplitude return log amplitude spectrum from cepstrum. // Note: This function requires symmetric cepstrum as the argument. func Cepstrum2LogAmplitude(ceps []float64) []float64 { return gossp.ToReal(fft.FFTReal(ceps)) }