diff --git a/Makefile b/Makefile index fd3b19b..92ad903 100755 --- a/Makefile +++ b/Makefile @@ -40,6 +40,6 @@ lint: golint . clean: - rm -f build - rm -rf internal/resources + - rm -r build + - rm -rf internal/resources diff --git a/gopow.go b/gopow.go index f59cba9..67eae4b 100644 --- a/gopow.go +++ b/gopow.go @@ -14,7 +14,7 @@ func main() { app := cli.NewApp() app.Name = "RTL GoPow" app.Usage = "Render a rtl_power CSV output as waterfall image" - app.Version = "0.0.2" + app.Version = "0.0.3" app.Author = "github.com/dhogborg" app.Email = "d@hogborg.se" @@ -68,6 +68,16 @@ func main() { Value: "png", Usage: "Output file format, default png [png,jpeg]", }, + cli.Float64Flag{ + Name: "max-power", + Value: 0, + Usage: "Define a manual maximum power (format nn.n)", + }, + cli.Float64Flag{ + Name: "min-power", + Value: 0, + Usage: "Define a manual minimum power (format nn.n)", + }, cli.BoolFlag{ Name: "verbose", Usage: "Enable more verbose output", diff --git a/internal/gopow/gopow.go b/internal/gopow/gopow.go index e0c8fd6..fc3674a 100644 --- a/internal/gopow/gopow.go +++ b/internal/gopow/gopow.go @@ -13,11 +13,17 @@ import ( "github.com/dustin/go-humanize" ) +const ( + PowerConfigAuto = -9813 +) + type RunConfig struct { InputFile string OutputFile string Format string Annotations bool + MaxPower float64 + MinPower float64 } type GoPow struct { @@ -33,6 +39,15 @@ func NewGoPow(c *cli.Context) (*GoPow, error) { OutputFile: c.String("output"), Format: c.String("format"), Annotations: !c.Bool("no-annotations"), + MaxPower: c.Float64("max-power"), + MinPower: c.Float64("min-power"), + } + + if !c.IsSet("max-power") { + config.MaxPower = PowerConfigAuto + } + if !c.IsSet("min-power") { + config.MinPower = PowerConfigAuto } if config.InputFile == "" { @@ -66,10 +81,20 @@ func NewGoPow(c *cli.Context) (*GoPow, error) { func (g *GoPow) Render() error { + conf := &RenderConfig{} + + if g.config.MaxPower != PowerConfigAuto { + conf.MaxPower = &g.config.MaxPower + } + + if g.config.MinPower != PowerConfigAuto { + conf.MinPower = &g.config.MinPower + } + log.Debug("staring render") g.timestamp = time.Now() - table, err := NewTable(g.config.InputFile) + table, err := NewTable(g.config.InputFile, conf) if err != nil { return err } @@ -77,7 +102,7 @@ func (g *GoPow) Render() error { g.image = table.Image() for y, row := range table.Rows { - for x, _ := range row.Samples { + for x := range row.Samples { g.image.Set(x, y, table.ColorAt(x, y)) } } diff --git a/internal/gopow/table.go b/internal/gopow/table.go index eb46778..f3bcd22 100644 --- a/internal/gopow/table.go +++ b/internal/gopow/table.go @@ -16,13 +16,11 @@ import ( ) type TableComplex struct { - File string // our input file + File string // our input file + Config *RenderConfig Rows []*LineComplex - Min float64 // minimum power value, used for color rendering - Max float64 // maximum dito - Bins int // horizontal slots, columns, bandwidth Integrations int // vertical slots, rows @@ -33,11 +31,19 @@ type TableComplex struct { TimeEnd *time.Time } -func NewTable(file string) (*TableComplex, error) { +// RenderConfig overrides automaticly calculated defaults +type RenderConfig struct { + MinPower *float64 // minimum power value, used for color rendering + MaxPower *float64 // maximum dito +} + +func NewTable(file string, conf *RenderConfig) (*TableComplex, error) { log.Debug("creating table") - t := &TableComplex{} + t := &TableComplex{ + Config: conf, + } err := t.Load(file) if err != nil { @@ -70,8 +76,8 @@ func (t *TableComplex) Load(file string) error { func (t *TableComplex) parseBuffer(filebuffer []byte) []*LineComplex { - t.Max = float64(math.MaxFloat64 * -1) - t.Min = float64(math.MaxFloat64) + var max = float64(math.MaxFloat64 * -1) + var min = float64(math.MaxFloat64) lines := bytes.Split(filebuffer, []byte("\n")) @@ -100,11 +106,11 @@ func (t *TableComplex) parseBuffer(filebuffer []byte) []*LineComplex { rows = append(rows, row) - if t.Min > row.LowSample() { - t.Min = row.LowSample() + if min > row.LowSample() { + min = row.LowSample() } - if t.Max < row.HighSample() { - t.Max = row.HighSample() + if max < row.HighSample() { + max = row.HighSample() } t.HzLow = row.HzLow @@ -134,9 +140,17 @@ func (t *TableComplex) parseBuffer(filebuffer []byte) []*LineComplex { sort.Sort(LineSort(rows)) + if t.Config.MaxPower == nil { + t.Config.MaxPower = &max + } + + if t.Config.MinPower == nil { + t.Config.MinPower = &min + } + log.WithFields(log.Fields{ - "pMax": t.Max, - "pMin": t.Min, + "pMax": *t.Config.MaxPower, + "pMin": *t.Config.MinPower, }).Debug("integrated lines") t.Integrations = len(rows) @@ -185,14 +199,21 @@ func (t *TableComplex) ColorAt(x, y int) color.Color { cell := t.Rows[y].Sample(x) - hue_start := 236.0 - hue_end := 0.0 + hueStart := 236.0 + hueEnd := 0.0 - span := (t.Min - t.Max) * -1 - h_per_deg := (hue_start - hue_end) / span - pow_normalized := cell - t.Min - pow_degrees := pow_normalized * h_per_deg - hue := hue_start - pow_degrees + span := (*t.Config.MinPower - *t.Config.MaxPower) * -1 + hPerDeg := (hueStart - hueEnd) / span + powNormalized := cell - *t.Config.MinPower + powDegrees := powNormalized * hPerDeg + hue := hueStart - powDegrees + + if hue > hueStart { + hue = hueStart + } + if hue < hueEnd { + hue = hueEnd + } return colorful.Hsv(hue, 1, 0.90)