見出し画像

RTL−SDRとGO言語で電波を受信する実験(5):地デジとNACK5の波形を表示できた

今朝は久しぶりに4時から開発開始です。昨日から作り始めたRTL-SDRで電波の波形を表示するプログラムの続きです。

処理の流れ

のような処理ですが、

package main

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"time"

	"github.com/samuel/go-rtlsdr/rtl"

	"github.com/go-echarts/go-echarts/v2/charts"
	"github.com/go-echarts/go-echarts/v2/opts"
)

func main() {
	freq := "79.5M"
	if len(os.Args) > 1 {
		freq = os.Args[1]
	}
	hz, err := getHz(freq)
	if err != nil {
		log.Fatalf("%v", err)
	}
	dev, err := rtl.Open(0)
	if err != nil {
		log.Fatalf("rtl.Open Failed to open device err=%v", err)
	}
	defer dev.Close()
	// no direct sample
	// no offset tuning
	// set auto gain
	if err := dev.SetTunerGainMode(false); err != nil {
		log.Fatalf("dev.SetTunerGainMode err=%v", err)
	}
	// no PPM
	// disable biasTee
	if err := dev.SetBiasTee(false); err != nil {
		log.Fatalf("dev.SetBiasTee err=%v", err)
	}
	// reset buffer
	if err := dev.ResetBuffer(); err != nil {
		log.Fatalf("dev.ResetBuffer err=%v", err)
	}
	// set sample rate 1MHz
	if err := dev.SetSampleRate(1_000_000); err != nil {
		log.Fatalf("dev.ResetBuffer err=%v", err)
	}
	// set center freq
	if err := dev.SetCenterFreq(hz); err != nil {
		log.Fatalf("dev.SetCenterFreq err=%v", err)
	}
	if cf, err := dev.CenterFreq(); err == nil {
		log.Printf("CenterFreq=%d", cf)
	}
	// wait 5mSec
	time.Sleep(time.Millisecond * 5)
	dmy := make([]byte, 1<<12)
	n, err := dev.Read(dmy)
	if err != nil {
		log.Fatalf("dev.Read dumy err=%v", err)
	}
	log.Printf("dumy read=%d", n)
	// read data
	buf := make([]byte, 16384)
	n, err = dev.Read(buf)
	if err != nil {
		log.Fatalf("dev.Read err=%v", err)
	}
	xaxis := []int{}
	data := []opts.LineData{}
	for i := 0; i < n; i++ {
		xaxis = append(xaxis, i)
		data = append(data, opts.LineData{Value: int(buf[i]) - 127})
	}
	showChart(freq, xaxis, data)
}

func getHz(s string) (uint, error) {
	if len(s) < 1 {
		return 0, fmt.Errorf("bad frequency")
	}
	last := s[len(s)-1:]
	suff := float64(1.0)
	switch last {
	case "g", "G":
		suff *= 1e3
		fallthrough
	case "m", "M":
		suff *= 1e3
		fallthrough
	case "k", "K":
		suff *= 1e3
		f, err := strconv.ParseFloat(s[0:len(s)-1], 64)
		if err != nil {
			return 0, err
		}
		return uint(f * suff), nil
	}
	f, err := strconv.ParseFloat(s, 64)
	if err != nil {
		return 0, err
	}
	return uint(f), nil
}

func showChart(freq string, xaxis []int, data []opts.LineData) {
	line := charts.NewLine()
	line.SetGlobalOptions(
		charts.WithTitleOpts(opts.Title{Title: freq + "Hz Signal by RTL-SDR"}),
		charts.WithToolboxOpts(opts.Toolbox{
			Show:  true,
			Right: "10%",
			Feature: &opts.ToolBoxFeature{
				SaveAsImage: &opts.ToolBoxFeatureSaveAsImage{
					Show:  true,
					Type:  "png",
					Title: "Save to Image",
				},
				DataZoom: &opts.ToolBoxFeatureDataZoom{
					Show: true,
				},
			}},
		),
	)
	line.SetXAxis(xaxis).
		AddSeries("signal", data)
	f, _ := os.Create(freq + "Hz.html")
	line.Render(f)
	defer f.Close()
}

のようなソースコードで実現できました。
NACK5のFM放送は、

NACK5の波形

チャートのズーム機能が使えるので

波形のズーム

のように分析できます。FMぽいです。
電波のないところは、

電波のないところ

で、たぶん地デジは

たぶん地デジ

のような感じで信号が強いです。
なんとなく電波が受信できている感じで楽しくなってきました。
本題のrtlsdr_powerのGO言語の写経ができそうです。
元のC言語のソースコードを読むと、

  • サンプリングが1M- 2M サンプル/秒

  • 周波数範囲 24MHz ー 1.67Ghz

なら、RTL-SDRのチューナーを使ってFFTの処理とかしないで周波数毎のパワーを測定できそうです。
早く作りたいところですが、今朝は時間切れです。

明日に続く

開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。