Exemple #1
0
// 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
}
Exemple #2
0
// 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
}
Exemple #3
0
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
}
Exemple #4
0
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
}
Exemple #5
0
// 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
}
Exemple #6
0
// 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
}
Exemple #7
0
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
}
Exemple #8
0
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
	}
}
Exemple #9
0
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
}
Exemple #10
0
// 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
		}
	}
}
Exemple #12
0
// Return the real and imaginary parts of the fft
func (d *DataFrame) FFT() []complex128 {
	data := d.Data()

	return fft.FFTReal(data)
}
Exemple #13
0
// 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))
}