Documentation
¶
Overview ¶
Package playground is the go-fft WebAssembly playground: a go-widgets canvas application in which a visitor builds a signal, picks a transform and sees what github.com/go-fft/fft makes of it — computed by go-fft itself, compiled to WebAssembly, with no JavaScript FFT anywhere.
The package is tagless and native-testable. dsp.go is the model (signals, transforms, the round trip and the timing), codegen.go writes the Go and the numpy equivalent of a configuration, viewmodel.go holds every piece of UI state as go-widgets/mvvm observables, and scene.go is the View: toolkit widgets bound to the view-model. cmd/playground-wasm is the thin js/wasm shell.
Index ¶
- Constants
- Variables
- func Factor(n int) string
- func FormatSamples(x []float64) string
- func Generate(p SignalParams) []float64
- func GoCode(c Config, n int) string
- func NumpyCode(c Config, n int) string
- func ParseSamples(s string) ([]float64, error)
- func SetupText(scale float64)
- func Smooth(n int) bool
- type Config
- type Curve
- type CurveStyle
- type Palette
- type Precision
- type Preset
- type Result
- type Scene
- func (s *Scene) AnimationStep(float64) bool
- func (s *Scene) Char(ch string) bool
- func (s *Scene) Click(x, y int) bool
- func (s *Scene) Context(int, int) bool
- func (s *Scene) Draw(buf []byte)
- func (s *Scene) KeyDown(code string) bool
- func (s *Scene) Move(x, y int) bool
- func (s *Scene) Paste(text string) bool
- func (s *Scene) Rects() map[string]toolkit.Rect
- func (s *Scene) Release(x, y int) bool
- func (s *Scene) Resize(cw, ch int) (int, int)
- func (s *Scene) Scroll(x, y, _, dy int) bool
- func (s *Scene) SetPalette(p Palette)
- func (s *Scene) Size() (int, int)
- func (s *Scene) Theme() *toolkit.Theme
- type SignalParams
- type Timing
- type Transform
- type View
- type ViewModel
- type Window
Constants ¶
const MaxListed = 4096
MaxListed is the longest signal whose samples the editor lists. A million numbers in a text box helps nobody and costs a second to lay out.
const MaxN = 1 << 20
MaxN is the longest signal the playground accepts: long enough to show that a big transform is fast, short enough that a careless paste cannot hang a tab.
Variables ¶
var ( LightPalette = Palette{ Background: toolkit.RGB(0xff, 0xff, 0xff), Surface: toolkit.RGB(0xf7, 0xf8, 0xfb), Ink: toolkit.RGB(0x0f, 0x11, 0x15), Line: toolkit.RGB(0xe7, 0xe9, 0xee), Border: toolkit.RGB(0xcf, 0xd4, 0xdd), Accent: toolkit.RGB(0x04, 0x78, 0x57), } DarkPalette = Palette{ Background: toolkit.RGB(0x0b, 0x0e, 0x14), Surface: toolkit.RGB(0x14, 0x1a, 0x24), Ink: toolkit.RGB(0xe6, 0xed, 0xf3), Line: toolkit.RGB(0x23, 0x2a, 0x36), Border: toolkit.RGB(0x3a, 0x45, 0x56), Accent: toolkit.RGB(0x34, 0xd3, 0x99), } )
LightPalette and DarkPalette are the landing's own tokens (--bg, --bg-soft, --ink, --line, --elev-border and --accent from the shared landing stylesheet, with go-fft's [params.brand] accent). They are the fallback for a host that passes none, and what the native tests draw with.
var NormNames = []string{"backward", "ortho", "forward"}
NormNames are numpy's names for the three fft.Norm values, in Norm order.
var PrecisionNames = []string{"float64 (complex128)", "float32 (complex64)"}
PrecisionNames are the precisions in Precision order.
var PresetNames = []string{"Sum of two sines", "Chirp f1 → f2", "Square wave", "Noise + tone", "Impulse", "Custom samples"}
PresetNames are the presets in Preset order, as the picker lists them.
var TransformNames = []string{"FFT", "IFFT", "RFFT", "IRFFT", "DCT", "IDCT", "DST", "IDST"}
TransformNames are the transforms in Transform order, as the picker lists them.
var TypeNames = []string{"Type I", "Type II", "Type III", "Type IV"}
TypeNames are the DCT/DST types as the picker lists them (index 0 is type I).
var ViewNames = []string{"Magnitude |y|", "Magnitude (dB)", "Phase (rad)", "Real and imaginary"}
ViewNames are the views in View order.
var WindowNames = []string{"None (rectangular)", "Hann", "Hamming", "Blackman", "Blackman–Harris", "Bartlett"}
WindowNames are the windows in Window order.
Functions ¶
func Factor ¶
Factor describes n as a product of primes ("2^4 · 3^4", "prime") — which decides how go-fft takes it: lengths whose prime factors are all at most 13 run on the mixed-radix Stockham engine, the others through Rader's or Bluestein's algorithm.
func FormatSamples ¶
FormatSamples writes samples back as text ParseSamples reads, eight to a line, each with the shortest representation that round-trips.
func Generate ¶
func Generate(p SignalParams) []float64
Generate returns the N samples of a preset signal:
- sines: A1·sin(2π·F1·t) + A2·sin(2π·F2·t)
- chirp: A1·sin(2π·(F1·t + (F2−F1)·t²/(2T))), a linear sweep over T = N/Fs
- square: ±A1 at F1 (the sign of sin(2π·F1·t), +A1 at zero)
- noise: Gaussian noise of standard deviation A1, plus A2·sin(2π·F1·t)
- impulse: A1 at n = 0, zero elsewhere
with t = n/Fs. The noise is seeded, so a configuration always draws the same samples. PresetCustom has no generator: it returns nil.
func GoCode ¶
GoCode is the Go program fragment that computes what c computes on an n-sample input x — the exact go-fft calls, so a visitor can copy it.
func ParseSamples ¶
ParseSamples reads numbers separated by commas, semicolons, spaces or new lines — what a pasted numpy array, CSV column or Go slice literal looks like. Brackets, braces and a leading "[]float64" are ignored, so `[1, 2, 3]` and `[]float64{1, 2, 3}` both parse. A line starting with # is a comment.
func SetupText ¶
func SetupText(scale float64)
SetupText installs the toolkit's metric scale and an anti-aliased face at that scale. The wasm shell calls it with window.devicePixelRatio BEFORE NewScene, so every metric the layout reads is already scaled: one logical pixel is one CSS pixel, drawn at device resolution.
Types ¶
type Config ¶
type Config struct {
Transform Transform
Type int // DCT/DST type, 1..4
Norm fft.Norm
Window Window
Precision Precision
Shift bool // FFTShift the FFT's output and its frequencies
Fs float64
}
Config is everything that decides what transform runs on the input.
type Curve ¶
type Curve struct {
Label string
X, Y []float64
Style CurveStyle
}
Curve is one plotted series, in the view-model's own terms: the View turns it into a toolkit plot series. The view-model imports no widget.
type CurveStyle ¶
type CurveStyle int
CurveStyle is how a curve is drawn: joined, or as stems from zero.
const ( CurveLine CurveStyle = iota CurveStem )
type Palette ¶
Palette is the handful of colours the page's stylesheet defines; the host reads them from the CSS custom properties, so the canvas wears exactly the landing's light or dark theme and its brand accent.
type Result ¶
type Result struct {
// Input is what was transformed: the samples after the window, or for
// IRFFT the N/2+1 values taken as a half spectrum.
Input []float64
// Re and Im are the output; Im is nil for a real-valued transform.
Re, Im []float64
// Axis is the abscissa of each output value, and AxisName its unit:
// frequency in Hz for a forward FFT/RFFT, time in seconds for the
// inverse FFTs, the coefficient index k for the DCT and DST.
Axis []float64
AxisName string
// RoundTrip is the largest |input − inverse(forward(input))|, the
// inverse being run with the same Norm and precision.
RoundTrip float64
}
Result is one run of a transform.
type Scene ¶
type Scene struct {
// contains filtered or unexported fields
}
Scene is the View: the toolkit widget tree, bound to a ViewModel, and the small amount of host bookkeeping a canvas application needs (the size, the pointer capture, a repaint flag). It implements go-widgets/webcanvas's App, Resizer, Scroller and Animator, so the wasm shell is one webcanvas.Run call.
func NewScene ¶
NewScene builds the widget tree for a w×h device-pixel surface and binds it to vm. Call SetupText first.
func (*Scene) AnimationStep ¶
AnimationStep repaints when something outside an input event changed the scene — the theme, a paste, a binding — and costs nothing otherwise.
func (*Scene) KeyDown ¶
KeyDown is a named key. A single character here is a shortcut (the shell sends ⌘V as "v"): it is left to the browser, which turns copy and paste into the events the host forwards to Paste.
func (*Scene) Paste ¶
Paste inserts text from the system clipboard where the keyboard is: the sample editor takes it whole (a pasted column of numbers), a field takes its first line.
func (*Scene) Rects ¶
Rects names the on-screen rectangle of each control, in device pixels, for a test harness that drives the page with synthetic events.
func (*Scene) Resize ¶
Resize relays the scene out for a canvas of cw×ch CSS pixels, returning the device-pixel size it renders at (the CSS size times the metric scale).
func (*Scene) SetPalette ¶
SetPalette recolours the scene: the host calls it at start and whenever the page's theme flips.
type SignalParams ¶
type SignalParams struct {
Preset Preset
N int
Fs float64
F1, F2 float64
A1, A2 float64
Seed uint64
}
SignalParams describes a generated signal. N samples taken at Fs Hz; F1, F2, A1 and A2 are read by each preset as its doc says.
type Timing ¶
Timing is how long one transform took, measured over Runs repetitions.
func Time ¶
Time runs the forward transform of c on x repeatedly — doubling the count until the batch takes at least budget — and reports the time per call. A single call to a tiny transform is far below the browser clock's resolution (performance.now is coarsened to 0.1 ms or worse), so one run would measure the clock, not the transform. now is the clock (time.Now in production).
type Transform ¶
type Transform int
Transform names a transform the playground runs.
func (Transform) ComplexOut ¶
ComplexOut reports whether t returns complex values.
type ViewModel ¶
type ViewModel struct {
// The signal.
Preset *mvvm.Observable[int]
N *mvvm.Observable[string]
Fs *mvvm.Observable[string]
F1, F2 *mvvm.Observable[string]
A1, A2 *mvvm.Observable[string]
Samples *mvvm.Observable[string]
// The transform.
Transform *mvvm.Observable[int]
Type *mvvm.Observable[int]
Window *mvvm.Observable[int]
Norm *mvvm.Observable[int]
Precision *mvvm.Observable[int]
View *mvvm.Observable[int]
Shift *mvvm.Observable[bool]
// Derived: written by recompute alone.
InputCurves *mvvm.ObservableList[Curve]
OutputCurves *mvvm.ObservableList[Curve]
InputAxis *mvvm.Observable[string]
OutputAxis *mvvm.Observable[string]
OutputTitle *mvvm.Observable[string]
Length *mvvm.Observable[string] // "N = 1009 (prime) · Rader/Bluestein"
Accuracy *mvvm.Observable[string] // the round trip
Speed *mvvm.Observable[string] // the timing
Problem *mvvm.Observable[string] // why nothing could be computed, or ""
GoCode *mvvm.Observable[string]
NumpyCode *mvvm.Observable[string]
// Commands.
CopyGo *mvvm.Command
CopyNumpy *mvvm.Command
// Clipboard receives the text a Copy command copies; the host installs
// it (navigator.clipboard in a browser). Nil copies nothing.
Clipboard func(string)
// Now is the clock the timing reads (time.Now unless a test swaps it).
Now func() time.Time
// Budget is how long the timing keeps repeating a transform.
Budget time.Duration
// contains filtered or unexported fields
}
ViewModel holds every piece of the playground's state as go-widgets/mvvm observables, and derives the plots, the numbers and the code from them. It references no widget; scene.go binds the widgets to it.
func NewViewModel ¶
func NewViewModel() *ViewModel
NewViewModel builds the view-model with the opening configuration — two sines in 1 000 samples at 1 kHz, an RFFT, a Hann window — and computes it.
type Window ¶
type Window int
Window names a window applied to the input before the transform.
func (Window) Coefficients ¶
Coefficients returns the window's n coefficients, from go-fft; nil for none.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
playground-wasm
command
The real entry point is wasm-only (main.go); this stub keeps `go build ./...` and `go test ./...` green on every native host.
|
The real entry point is wasm-only (main.go); this stub keeps `go build ./...` and `go test ./...` green on every native host. |