ソースを参照

Split span zoom from sample rate control

master
Jan Svabenik 5日前
コミット
57f9b6d8cc
4個のファイルの変更56行の追加9行の削除
  1. +5
    -0
      cmd/sdrd/main.go
  2. +14
    -4
      internal/sdrplay/sdrplay.go
  3. +23
    -4
      web/app.js
  4. +14
    -1
      web/index.html

+ 5
- 0
cmd/sdrd/main.go ファイルの表示

@@ -363,6 +363,7 @@ func runDSP(ctx context.Context, src sdr.Source, cfg config.Config, det *detecto
dcEnabled := cfg.DCBlock
iqEnabled := cfg.IQBalance

gotSamples := false
for {
select {
case <-ctx.Done():
@@ -385,6 +386,10 @@ func runDSP(ctx context.Context, src sdr.Source, cfg config.Config, det *detecto
log.Printf("read IQ: %v", err)
continue
}
if !gotSamples {
log.Printf("received IQ samples")
gotSamples = true
}
if dcEnabled {
dcBlocker.Apply(iq)
}


+ 14
- 4
internal/sdrplay/sdrplay.go ファイルの表示

@@ -70,6 +70,7 @@ import (
"fmt"
"runtime/cgo"
"sync"
"time"
"unsafe"

"sdr-visual-suite/internal/sdr"
@@ -134,6 +135,11 @@ func (s *Source) configure(sampleRate int, centerHz float64, gainDb float64) err
if err := cErr(C.sdrplay_api_Init(s.dev.dev, &cb, unsafe.Pointer(uintptr(s.handle)))); err != nil {
return fmt.Errorf("sdrplay_api_Init: %w", err)
}
// Apply initial settings explicitly to ensure streaming starts.
updateReasons := C.int(C.sdrplay_api_Update_Dev_Fs | C.sdrplay_api_Update_Tuner_Frf | C.sdrplay_api_Update_Tuner_Gr | C.sdrplay_api_Update_Ctrl_Agc)
if err := cErr(C.sdrplay_update(unsafe.Pointer(s.dev.dev), updateReasons)); err != nil {
return fmt.Errorf("sdrplay_api_Update: %w", err)
}
return nil
}

@@ -200,11 +206,15 @@ func (s *Source) Stop() error {
}

func (s *Source) ReadIQ(n int) ([]complex64, error) {
buf := <-s.ch
if len(buf) >= n {
return buf[:n], nil
select {
case buf := <-s.ch:
if len(buf) >= n {
return buf[:n], nil
}
return buf, nil
case <-time.After(1500 * time.Millisecond):
return nil, errors.New("timeout waiting for IQ samples")
}
return buf, nil
}

//export goStreamCallback


+ 23
- 4
web/app.js ファイルの表示

@@ -16,6 +16,7 @@ const detailSpectrogram = document.getElementById('detailSpectrogram');
const configStatusEl = document.getElementById('configStatus');
const centerInput = document.getElementById('centerInput');
const spanInput = document.getElementById('spanInput');
const sampleRateSelect = document.getElementById('sampleRateSelect');
const fftSelect = document.getElementById('fftSelect');
const gainRange = document.getElementById('gainRange');
const gainInput = document.getElementById('gainInput');
@@ -87,7 +88,11 @@ function applyConfigToUI(cfg) {
if (!cfg) return;
isSyncingConfig = true;
centerInput.value = toMHz(cfg.center_hz).toFixed(6);
spanInput.value = toMHz(cfg.sample_rate).toFixed(3);
if (sampleRateSelect) {
sampleRateSelect.value = toMHz(cfg.sample_rate).toFixed(3).replace(/\.0+$/, '').replace(/\.$/, '');
}
const spanMHz = toMHz(cfg.sample_rate / zoom);
spanInput.value = spanMHz.toFixed(3);
fftSelect.value = String(cfg.fft_size);
gainRange.value = cfg.gain_db;
gainInput.value = cfg.gain_db;
@@ -214,6 +219,9 @@ function renderSpectrum() {
const span = sample_rate / zoom;
const startHz = center_hz - span / 2 + pan * span;
const endHz = center_hz + span / 2 + pan * span;
if (!isSyncingConfig && spanInput) {
spanInput.value = (span / 1e6).toFixed(3);
}

const minDb = -120;
const maxDb = 0;
@@ -465,11 +473,22 @@ centerInput.addEventListener('change', () => {

spanInput.addEventListener('change', () => {
const mhz = parseFloat(spanInput.value);
if (Number.isFinite(mhz) && mhz > 0) {
queueConfigUpdate({ sample_rate: Math.round(fromMHz(mhz)) });
}
if (!Number.isFinite(mhz) || mhz <= 0) return;
const baseRate = currentConfig ? currentConfig.sample_rate : (latest ? latest.sample_rate : 0);
if (!baseRate) return;
zoom = Math.max(0.25, Math.min(20, baseRate / fromMHz(mhz)));
timelineDirty = true;
});

if (sampleRateSelect) {
sampleRateSelect.addEventListener('change', () => {
const mhz = parseFloat(sampleRateSelect.value);
if (Number.isFinite(mhz) && mhz > 0) {
queueConfigUpdate({ sample_rate: Math.round(fromMHz(mhz)) });
}
});
}

fftSelect.addEventListener('change', () => {
const size = parseInt(fftSelect.value, 10);
if (Number.isFinite(size)) {


+ 14
- 1
web/index.html ファイルの表示

@@ -30,7 +30,20 @@

<label class="control-label" for="spanInput">Span (MHz)</label>
<div class="control-row">
<input id="spanInput" type="number" step="0.1" min="0.1" />
<input id="spanInput" type="number" step="0.05" min="0.05" />
</div>

<label class="control-label" for="sampleRateSelect">Sample Rate (MHz)</label>
<div class="control-row">
<select id="sampleRateSelect">
<option value="0.5">0.5</option>
<option value="1.0">1.0</option>
<option value="1.536">1.536</option>
<option value="2.048">2.048</option>
<option value="2.5">2.5</option>
<option value="3.072">3.072</option>
<option value="4.096">4.096</option>
</select>
</div>

<label class="control-label" for="fftSelect">FFT Size</label>


読み込み中…
キャンセル
保存