// Extract real parts, copy them from src to dst. // In the meanwhile, check if imaginary parts are nearly zero // and scale the kernel to compensate for unnormalized FFTs. func scaleRealParts(dst, src *data.Slice, scale float32) { util.Argument(2*dst.Len() == src.Len()) util.Argument(dst.NComp() == 1 && src.NComp() == 1) srcList := src.HostCopy().Host()[0] dstList := dst.Host()[0] // Normally, the FFT'ed kernel is purely real because of symmetry, // so we only store the real parts... maximg := float32(0.) maxreal := float32(0.) for i := 0; i < src.Len()/2; i++ { dstList[i] = srcList[2*i] * scale if fabs(srcList[2*i+0]) > maxreal { maxreal = fabs(srcList[2*i+0]) } if fabs(srcList[2*i+1]) > maximg { maximg = fabs(srcList[2*i+1]) } } // ...however, we check that the imaginary parts are nearly zero, // just to be sure we did not make a mistake during kernel creation. if maximg/maxreal > FFT_IMAG_TOLERANCE { log.Fatalf("Too large FFT kernel imaginary/real part: %v", maximg/maxreal) } }
func Image(f *data.Slice, fmin, fmax string) *image.NRGBA { dim := f.NComp() switch dim { default: log.Fatalf("unsupported number of components: %v", dim) case 3: return drawVectors(f.Vectors()) case 1: min, max := extrema(f.Host()[0]) if fmin != "auto" { m, err := strconv.ParseFloat(fmin, 32) util.FatalErr(err) min = float32(m) } if fmax != "auto" { m, err := strconv.ParseFloat(fmax, 32) util.FatalErr(err) max = float32(m) } return drawFloats(f.Scalars(), min, max) } panic("unreachable") }