func agm(a, g complex128) complex128 { for cmplx.Abs(a-g) > cmplx.Abs(a)*ε { a, g = (a+g)*.5, cmplx.Rect(math.Sqrt(cmplx.Abs(a)*cmplx.Abs(g)), (cmplx.Phase(a)+cmplx.Phase(g))*.5) } return a }
func mean_angle(deg []float64) float64 { sum := 0i for _, x := range deg { sum += cmplx.Rect(1, deg2rad(x)) } return rad2deg(cmplx.Phase(sum)) }
func logInterpolate(a complex128, b complex128, proportion float64) complex128 { // TODO - precalc arg/norm outside the loop. if cmplx.Abs(a) < cmplx.Abs(b) { return logInterpolate(b, a, 1-proportion) } z := b / a zArg := cmplx.Phase(z) if zArg > 0 { // aArg -> bArg, or aArg -> bArg + 2PI, whichever is closer if zArg > math.Pi { zArg -= 2 * math.Pi } } else { // aArg -> bArg, or aArg -> bArg - 2PI, whichever is closer if zArg < -math.Pi { zArg += 2 * math.Pi } } zLogAbs := math.Log(cmplx.Abs(z)) cArg, cLogAbs := zArg*proportion, zLogAbs*proportion cAbs := math.Exp(cLogAbs) return a * cmplx.Rect(cAbs, cArg) }
func TestGoertzel(t *testing.T) { samplerate := 1024 blocksize := 1024 freq := 128 samples := make([]float64, blocksize) w := 2 * math.Pi / float64(samplerate) for i := 0; i < blocksize; i++ { samples[i] = math.Sin(float64(i) * float64(freq) * w) } g := NewGoertzel([]uint64{128, 129}, samplerate, blocksize) g.Feed(samples) m := g.Magnitude() if e := math.Pow(float64(blocksize)/2, 2); !approxEqual(m[0], e, 1e-8) { t.Errorf("Goertzel magnitude = %f. Want %f", m[0], e) } if !approxEqual(float64(m[1]), 0.0, 1e-10) { t.Errorf("Foertzel magnitude = %f. Want 0.0", m[1]) } c := g.Complex() if e, m := math.Sqrt(math.Pow(float64(blocksize)/2, 2)), cmplx.Abs(complex128(c[0])); !approxEqual(m, e, 1e-8) { t.Errorf("Goertzel magnitude = %f. Want %f", m, e) } if e, p := -math.Pi/2, cmplx.Phase(complex128(c[0])); !approxEqual(p, e, 1e-12) { t.Errorf("Goertzel phase = %f. Want %f", p, e) } }
func complexToInt(a []complex128) []int { r := make([]int, len(a)) for n, v := range a { // Convert complex phase to percentage int r[n] = int(((cmplx.Phase(v) + math.Pi) / math.Pi) * 100) } return r }
// HSLWheelMap generates a ColorMap from a ComplexMap, using a the HSL color // space with the Argument of the point as the hue, and a nonlinear mapping of // the absolute value of the point as the lightness. func HSLWheelMap(fnc ComplexMap) ColorMap { return func(point complex128) color.Color { val := fnc(point) add := math.Pow(cmplx.Abs(val), 2.0) // map to [0,1] L := add / (add + 1.0) // See wikipedia. This is a fairly bad implementation of the algorithm. H := (3.0 * cmplx.Phase(point) / math.Pi) + 3.0 // Get the values being used C := (1.0 - math.Abs(2.0*L-1.0)) X := C * (1.0 - math.Abs(math.Mod(H, 2.0)-1.0)) // Giant semi-conditional, again, see wikipedia. var R1, G1, B1 float64 switch math.Floor(H) { case 0: R1 = C G1 = X case 1: R1 = X G1 = C case 2: G1 = C B1 = X case 3: G1 = X B1 = C case 4: R1 = X B1 = C case 5: R1 = C B1 = X default: // Pass on this, 0 initialization is good. } // m is the "minimum" value of each color. m := (L - C/2.0) // Convert from [0,1] RGB to [0,255] RGB (and add m while we're at it). r := round(255.0 * (R1 + m)) g := round(255.0 * (G1 + m)) b := round(255.0 * (B1 + m)) // We're done. Replace all of the above once Go adds HSL support. return color.RGBA{r, g, b, 255} } }
func (s *Soldier) Step() { ref := s.refPoint() switch s.Current { case Halt: case ForwardMarch: s.Pt += complex(vel, 0)*s.Dir - ref*complex(gain, 0) + complex(velRand, 0)*complex(rand.Float64(), rand.Float64()) s.P.Move(real(s.Pt), imag(s.Pt)) case LeftWheel: v := velMax if s.Adj[0] == nil { _, cols := s.C.f.RowCols(len(s.C.s)) v *= float64(cols-s.Col()+1) / float64(cols+1) th := velMax / (2 * math.Pi * float64(cols+1)) s.Dir *= cmplx.Rect(1, th) } else { v = vel } s.Pt += complex(v, 0)*s.Dir - ref*complex(gain, 0) + complex(velRand, 0)*complex(rand.Float64(), rand.Float64()) s.P.Move(real(s.Pt), imag(s.Pt)) case RightWheel: v := velMax if s.Adj[0] == nil { _, cols := s.C.f.RowCols(len(s.C.s)) v *= float64(s.Col()+1) / float64(cols+1) th := velMax / (2 * math.Pi * float64(cols+1)) s.Dir *= cmplx.Rect(1, -th) } else { v = vel } s.Pt += complex(v, 0)*s.Dir - ref*complex(gain, 0) + complex(velRand, 0)*complex(rand.Float64(), rand.Float64()) s.P.Move(real(s.Pt), imag(s.Pt)) // case LeftTurn, RightTurn: // s.Color() case Reform: s.Pt -= ref*complex(gainRef, 0) - complex(velRand, 0)*complex(rand.Float64(), rand.Float64()) s.P.Move(real(s.Pt), imag(s.Pt)) if cmplx.Abs(s.Pt-ref) < 0.1 { s.Orders(Halt) } } if s.Adj[0] != nil { s.Dir = cmplx.Rect(1, cmplx.Phase(s.Adj[0].Position()-s.Position())) } }
/* Calculates a color value from a complex number. Brightness is inverse to the distance from 0. Color value is dependent on the angle from the real axis, starting with red. */ func calculateColor(value complex128) Color { // See Wikipedia // http://en.wikipedia.org/wiki/Complex_number#Absolute_value_and_argument saturation := cmplx.Abs(value) // Assume that 2.2 is the max abs we can get, because sqrt(2*2 + 1) ~ 2.2 saturation /= 2.2 phase := cmplx.Phase(value) // Phase in [-Pi, Pi] if phase < 0 { phase = 2*math.Pi + phase } hue := phase / (2 * math.Pi) return hsv.Hsv2rgb(HSVColor{hue, saturation, 1}) }
// Angle determine the angle(radian) of two vectors func Angle(u, v complex128) float64 { return cmplx.Phase(u / v) }
func mapColor(ct, limit int, z complex128) color.RGBA { if ct == 0 { return hsv(cmplx.Phase(z), 1.0, 1.0) } return hsv(cmplx.Phase(z), 1.0, 0.2) }
// Return information about analysed frequency k. func (a Analysis) Info(k int) (frequency float64, amplitude float64, phase float64) { n := float64(len(a.Data)) frequency = a.SampleRate * float64(k) / n x := a.Data[k] return frequency, cmplx.Abs(x) / n, -cmplx.Phase(x) }
// PolarDiscriminator returns the phase angle between two complex vectors // equivalent to arg(a * conj(b)). The returned angle is in the range [-Pi, Pi]. func PolarDiscriminator(a, b complex128) float64 { return cmplx.Phase(a * cmplx.Conj(b)) }
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 }
func (o Scomplex128) Angle() RealNum { return Sfloat64(cmplx.Phase(complex128(o))) }