package dsp import ( "math" "testing" "time" "github.com/jan/fm-rds-tx/internal/output" ) func TestResampleIQIdentity(t *testing.T) { frame := &output.CompositeFrame{ Samples: make([]output.IQSample, 100), SampleRateHz: 228000, Timestamp: time.Now(), } for i := range frame.Samples { frame.Samples[i] = output.IQSample{I: float32(i) / 100, Q: 0} } result := ResampleIQ(frame, 228000) if len(result.Samples) != 100 { t.Fatalf("expected 100, got %d", len(result.Samples)) } } func TestResampleIQUpsample(t *testing.T) { frame := &output.CompositeFrame{ Samples: make([]output.IQSample, 228), SampleRateHz: 228000, Timestamp: time.Now(), } for i := range frame.Samples { phase := 2 * math.Pi * float64(i) / float64(len(frame.Samples)) frame.Samples[i] = output.IQSample{I: float32(math.Cos(phase)), Q: float32(math.Sin(phase))} } result := ResampleIQ(frame, 528000) expectedLen := int(float64(228) * 528000 / 228000) if math.Abs(float64(len(result.Samples)-expectedLen)) > 2 { t.Fatalf("expected ~%d samples, got %d", expectedLen, len(result.Samples)) } if result.SampleRateHz != 528000 { t.Fatalf("expected rate 528000, got %.0f", result.SampleRateHz) } // Verify magnitude preserved (should be ~1.0 for unit circle) for i := 10; i < len(result.Samples)-10; i++ { s := result.Samples[i] mag := math.Sqrt(float64(s.I)*float64(s.I) + float64(s.Q)*float64(s.Q)) if mag < 0.9 || mag > 1.1 { t.Fatalf("sample %d: magnitude=%.4f", i, mag) } } } func TestResampleIQNil(t *testing.T) { if ResampleIQ(nil, 528000) != nil { t.Fatal("expected nil") } }