Sounddevice ValueError: не удалось передать входной массив из формы (2048) в форму (2048,1) - PullRequest
0 голосов
/ 15 декабря 2018

Я знаю, что может показаться, что это еще одна из тех публикаций ValueError, но, пожалуйста, выслушайте меня и поймите, что я пробовал поискать в Google и просматривал сообщество StackOverflow, чтобы найти реальное решение для моей проблемы.

В настоящее время я нахожусьпытаюсь передать мои демодулированные сэмплы в модуль sounddevice и воспроизвести его в реальном времени, используя функцию callback .

Ошибка:

Файл "rtl-fm-cont.py", строка 120, в outdata audio_callback [:] = data ValueError: не удалось передатьвходной массив из формы (2048) в форму (2048,1)

Я приложил полный вывод этого кода ниже:

#!/usr/bin/env python

# library imports ...

parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-d', '--device', type=int_or_str,
                    help='output device (numeric ID or substring)')
parser.add_argument('-b', '--blocksize', type=int, default=2048,
                    help='block size (default: %(default)s)')
parser.add_argument(
    '-q', '--buffersize', type=int, default=20,
    help='number of blocks used for buffering (default: %(default)s)')
args = parser.parse_args()
if args.blocksize == 0:
    parser.error('blocksize must not be zero')
if args.buffersize < 1:
    parser.error('buffersize must be at least 1')

q = queue.Queue(maxsize=args.buffersize)
event = threading.Event()

device_index = RtlSdr.get_device_index_by_serial('00000001')

class fmDemodulator(object):
    # Called for each updates
    def __init__(self, sdr=None):
        self.sdr = sdr if sdr else RtlSdr(device_index)

    def Demod(self, *args):
        Fs = self.sdr.sample_rate
        # Fc = self.sdr.center_freq

        # Read IQ samples
        samples = self.sdr.read_samples(4*12*2048)
        print ('Fetching {} IQ samples from SDR #{}'.format(len(samples), device_index))
        # Convert sampled data into numpy array
        x1 = np.array(samples).astype("complex64")

        # Downmixed Baseband Signal (Adjust offset to be centered)
        offsetFreq = 0    # already centered
        fc1 = np.exp(-1.0j*2.0*np.pi* offsetFreq/Fs*np.arange(len(x1)))  
        x2 = x1 * fc1  

        # Filter and downsample the FM Radio Signal
        bwFM = 200000   # approx. 170 kHz for a single channel
        decRate = int(Fs/bwFM)
        x3 = signal.decimate(x2, decRate)
        newFs = Fs/decRate

        ### Demodulate 200kHz FM Signal
        # Polar discriminator
        y4 = x3[1:] * np.conj(x3[:-1])  
        x4 = np.angle(y4)  

        # The de-emphasis filter
        # Given a signal 'x4' (in a numpy array) with sampling rate newFS
        d = newFs * 75e-6   # Calculate the # of samples to hit the -3dB point  
        x = np.exp(-1/d)   # Calculate the decay between each sample  
        b = [1-x]          # Create the filter coefficients  
        a = [1,-x]  
        x5 = signal.lfilter(b,a,x4)  

        # Find a decimation rate to achieve audio sampling rate between 44-48 kHz
        audioFreq = 44100 
        dec_audio = int(newFs/audioFreq)  
        audioFs = newFs/dec_audio
        x6 = signal.decimate(x5, dec_audio) 

        # Scale audio to adjust volume
        x6 *= 10000 / np.max(np.abs(x6))  

        # debug
        print ('decRate: {}, newFs : {}, dec_audio: {}'.format(decRate, newFs, dec_audio))
        print ('Output audio: {} samples, audioFreq: {}, audioFs: {}'.format(len(x6), audioFreq, audioFs))

        return x6

# https://python-sounddevice.readthedocs.io/en/0.3.6/examples.html
def audio_callback(outdata, frames, time, status):
    """This is called (from a separate thread) for each audio block."""
    assert frames == args.blocksize
    if status.output_underflow:
        print('Output underflow: increase blocksize?', file=sys.stderr)
        raise sd.CallbackAbort
    assert not status
    try:
        data = q.get_nowait()
        print(data)
        print(data.dtype)
    except queue.Empty:
        print('Buffer is empty: increase buffersize?', file=sys.stderr)
        raise sd.CallbackAbort
    if len(data) < len(outdata):
        outdata[:len(data)] = data
        outdata[len(data):] = b'\x00' * (len(outdata) - len(data))
        raise sd.CallbackStop
    else:
        outdata[:] = data

def main():
    sdr = RtlSdr(device_index)
    fm = fmDemodulator(sdr)

    # SDR Configurations
    sdr.sample_rate = int(2.4e6)        # Hz
    sdr.center_freq = int(102e6)        # Hz
    sdr.freq_correction = 77            # PPM +- 20
    sdr.gain = 'auto'

    samplerate = 50000
    channels = 1
    try:
        for _ in range(args.buffersize):
            data = fm.Demod()
            if not np.any(data):
                break
            q.put_nowait(data) # pre-fill queue

        stream = sd.OutputStream(
            samplerate=samplerate, blocksize=args.blocksize,
            device=args.device, channels=channels, dtype='int16',
            callback=audio_callback, finished_callback=event.set)
        with stream:
            timeout = args.blocksize * args.buffersize / samplerate
            while np.any(data): # while data
                data = fm.Demod()
                q.put(data, timeout=timeout)
            event.wait()  # Wait until playback is finished
    except KeyboardInterrupt:
        parser.exit('\nInterrupted by user')
    except queue.Full:
        # A timeout occured, i.e. there was an error in the callback
        parser.exit(1)
    except Exception as e:
        parser.exit(type(e).__name__ + ': ' + str(e))

Вывод:

Output audio: 2048 samples, audioFreq: 44100, audioFs: 50000.0
Fetching 98304 IQ samples from SDR #0

...

Fetching 98304 IQ samples from SDR #0
decRate: 12, newFs : 200000.0, dec_audio: 4
Output audio: 2048 samples, audioFreq: 44100, audioFs: 50000.0
Fetching 98304 IQ samples from SDR #0
[  627.05045796  1835.36815837  3381.16496121 ...   401.43836645
 -1156.07050642 -1291.0900775 ]
float64
From cffi callback <function _StreamBase.__init__.<locals>.callback_ptr at 0x10eabbea0>:
Traceback (most recent call last):
  File "/Users/user/.local/lib/python3.6/site-packages/sounddevice.py", line 741, in callback_ptr
    return _wrap_callback(callback, data, frames, time, status)
  File "/Users/user/.local/lib/python3.6/site-packages/sounddevice.py", line 2517, in _wrap_callback
decRate: 12, newFs : 200000.0, dec_audio: 4
Output audio: 2048 samples, audioFreq: 44100, audioFs: 50000.0
    callback(*args)
  File "rtl-fm-cont.py", line 120, in audio_callback
    outdata[:] = data
ValueError: could not broadcast input array from shape (2048) into shape (2048,1)
Fetching 98304 IQ samples from SDR #0
decRate: 12, newFs : 200000.0, dec_audio: 4
Output audio: 2048 samples, audioFreq: 44100, audioFs: 50000.0

Ваша помощь будет высоко оценена.Заранее спасибо.

1 Ответ

0 голосов
/ 15 декабря 2018

Похоже на простое:

outdata[:] = data.reshape(2048,1)

numpy.reshape

Исправлена ​​проблема.

...