|
- package dsp
-
- import "math"
-
- // FMModulator converts a composite baseband signal into FM-modulated IQ samples.
- // The modulated output represents the instantaneous frequency deviation around
- // a zero-IF carrier (baseband IQ). For a real SDR transmitter the SDR hardware
- // then upconverts this to the desired center frequency.
- type FMModulator struct {
- // MaxDeviation is the peak frequency deviation in Hz (±75 kHz for FM broadcast).
- MaxDeviation float64
- SampleRate float64
-
- phase float64 // accumulated carrier phase in radians
- }
-
- // NewFMModulator creates a modulator with broadcast FM defaults.
- func NewFMModulator(sampleRate float64) *FMModulator {
- return &FMModulator{
- MaxDeviation: 75000, // ±75 kHz
- SampleRate: sampleRate,
- }
- }
-
- // Modulate converts a single composite sample (normalized to [-1,+1] representing
- // full deviation) into an IQ pair.
- func (m *FMModulator) Modulate(composite float64) (i, q float64) {
- // Instantaneous frequency offset = composite * maxDeviation
- // Phase increment per sample = 2π * freq_offset / sampleRate
- freqOffset := composite * m.MaxDeviation
- m.phase += 2 * math.Pi * freqOffset / m.SampleRate
-
- // Keep phase bounded to avoid float64 precision loss over long runs
- if m.phase > math.Pi {
- m.phase -= 2 * math.Pi * math.Floor((m.phase+math.Pi)/(2*math.Pi))
- }
-
- i = math.Cos(m.phase)
- q = math.Sin(m.phase)
- return i, q
- }
-
- // Reset clears the modulator phase.
- func (m *FMModulator) Reset() {
- m.phase = 0
- }
|