99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
package cwdecode
|
|
|
|
import (
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// reverse Morse map for the synthesizer.
|
|
func charToMorse() map[byte]string {
|
|
m := map[byte]string{}
|
|
for code, ch := range morse {
|
|
m[ch] = code
|
|
}
|
|
return m
|
|
}
|
|
|
|
// keyMessage synthesizes a clean keyed tone for msg at the given WPM/pitch.
|
|
func keyMessage(msg string, fs, wpm int, pitch float64) []int16 {
|
|
dot := fs * 1200 / (wpm * 1000) // samples per dot
|
|
c2m := charToMorse()
|
|
var out []int16
|
|
phase := 0.0
|
|
dphi := 2 * math.Pi * pitch / float64(fs)
|
|
|
|
tone := func(n int) {
|
|
for i := 0; i < n; i++ {
|
|
out = append(out, int16(9000*math.Sin(phase)))
|
|
phase += dphi
|
|
}
|
|
}
|
|
silence := func(n int) {
|
|
for i := 0; i < n; i++ {
|
|
out = append(out, 0)
|
|
}
|
|
}
|
|
|
|
silence(fs / 4) // 250 ms lead-in for AGC warmup
|
|
for i := 0; i < len(msg); i++ {
|
|
ch := msg[i]
|
|
if ch == ' ' {
|
|
silence(7 * dot)
|
|
continue
|
|
}
|
|
code := c2m[ch]
|
|
for j := 0; j < len(code); j++ {
|
|
if code[j] == '.' {
|
|
tone(dot)
|
|
} else {
|
|
tone(3 * dot)
|
|
}
|
|
silence(dot) // inter-element gap
|
|
}
|
|
silence(3 * dot) // inter-character gap (on top of the trailing element gap)
|
|
}
|
|
silence(fs / 4)
|
|
return out
|
|
}
|
|
|
|
func TestDecodeCleanSignal(t *testing.T) {
|
|
const fs = 16000
|
|
var sb strings.Builder
|
|
d := New(fs, func(s string) { sb.WriteString(s) }, nil)
|
|
|
|
// Repeat so AGC warm-up only costs the first word.
|
|
samples := keyMessage("PARIS PARIS PARIS", fs, 22, 700)
|
|
// Feed in small chunks like the live capture would.
|
|
for i := 0; i < len(samples); i += 256 {
|
|
end := i + 256
|
|
if end > len(samples) {
|
|
end = len(samples)
|
|
}
|
|
d.Process(samples[i:end])
|
|
}
|
|
|
|
got := strings.ToUpper(sb.String())
|
|
if !strings.Contains(got, "PARIS") {
|
|
t.Fatalf("decoded %q, want it to contain PARIS", got)
|
|
}
|
|
}
|
|
|
|
func TestDecodeNumbersAndProsign(t *testing.T) {
|
|
const fs = 16000
|
|
var sb strings.Builder
|
|
d := New(fs, func(s string) { sb.WriteString(s) }, nil)
|
|
samples := keyMessage("TEST 599 TEST", fs, 18, 650)
|
|
for i := 0; i < len(samples); i += 200 {
|
|
end := i + 200
|
|
if end > len(samples) {
|
|
end = len(samples)
|
|
}
|
|
d.Process(samples[i:end])
|
|
}
|
|
got := strings.ToUpper(sb.String())
|
|
if !strings.Contains(got, "599") {
|
|
t.Fatalf("decoded %q, want it to contain 599", got)
|
|
}
|
|
}
|