前回デシメーション処理が「出来た気」がしたので、後はPythonで行っている処理をScilabへ移植していけば音声でるんでないの?しかし、いけません。ザーという雑音。どこが悪いの?もう一度Pythonに戻ってステップバイステップで比較できるよう、中間データもScilabへ輸出することにいたしました。やり直しね。
※「手習ひデジタル信号処理」投稿順 Indexはこちら
※実験に使用したPythonソース全文は末尾に
音声ファイルのScilab上での再生
C:¥var¥Tx.csvなるファイルに、音声(16ビット符合付整数がならんだCSV形式)があった場合、以下にて音声再生することができます。
aFnam=fullfile("C:\var", "Tx.csv"); audio=csvRead(aFnam); playsnd(audio, Fa);
なお、今回オーディオ信号のサンプル周波数Faは44100Hzとしてます(Python上で素で再生したときよりファイルでScilabもってきた後の方が雑音きつくなった気がするのは何故?別途要調査。)
Scilab上での復調処理?不調。Pythonに戻る。
同様な変数に同様なデータが格納されていればplaysnd関数にて音声再生が可能です。前回の結果をうけて、後続のFM復調処理から再度のリサンプリング、そしてオーディオ形式への変換をチョコチョコっと行ってみたところ、イケません。
雑音しか聞こえんがや
原因追及方法は、Python上での処理とScilab上での処理をステップバイステップで比較することしか考えつかん、ということで、前近代的な手法で行くことにいたしました。そのため、以下の回で作成してあったRTL-SDRを使ってデータ断片を取得するPythonプログラムに再び手直しすることにいたしました(ソース全文は末尾に。)
手習ひデジタル信号処理(91) PythonでFMラジオデータを音声再生、RTL-SDR
修正後のPythonプログラムを使って、RTL-SDRで再びTokyo FM様の音声断片のデータを取得。プロフラム引数のデフォルトがTokyo FM様に向けてあるので何も指定しないとTokyo FMとなりまする。
今回取得の復調済音声データを再生すると以下が聞こえました。
『高速道路の下りは』(Tokyo FM様)
これをScilab上で聞こえるようにするのが目標ね。
なんとか音声聞こえるようにならんかのう。
手習ひデジタル信号処理(93) Scilab、デシメーション処理、実データで動作確認 へ戻る
手習ひデジタル信号処理(95) Scilab、Tokyo FMの再生、1秒ちょっと へ進む
※以下ソースは2023年7月27日改定
#!/usr/bin/python # coding: utf-8 ### @file pyrtlsdr2sci.py ### @brief save RTL-SDR IQ signal for scilab ### ### @author: Joseph Halfmoon ### @date: June 7, 2023 """ Save RTL-SDR IQ signal for scilab v0.3 input ===== --FS s sample rate (default=2.1168[MHz]) --FC c center_freq (defalut=80[MHz] --N n number of samples (defalut=2560, means 2560*1024) --FNAME x File name to save (defalut=toScilab.csv) --G opt 'psd' 'decimated' 'audio' --D f decimation factor -A play Audio -V VERSION """ import argparse import csv import math import matplotlib.pyplot as plt import numpy as np import os.path import scipy.signal import sys import pyaudio from rtlsdr import RtlSdr import wave versionSTR = "pyrtlsdr2sci.py v0.4 (July 20, 2023)" def parse2float(st): """parse string to float Returns at Fail: None """ try: work = float(st) except: return None return work def chkVal(arg, dval): vl = parse2float(arg) if vl is None: nLen = len(arg) if nLen > 1: bdy = arg[0:nLen-1] lastChar = arg[nLen-1] vl = parse2float(bdy) if vl is None: vl = dval else: lastChar = "0" return (vl, lastChar) def freqIN(arg, dval): prefixes = 'mkMG' vl, lastChar = chkVal(arg, dval) pfx = prefixes.find(lastChar) if pfx == 0: ex = 1e-3 elif pfx == 1: ex = 1e3 elif pfx == 2: ex = 1e6 elif pfx == 3: ex = 1e9 else: ex = 1 return vl * ex def parse2int(st): """parse string to int Returns at Fail: None """ try: work = int(st) except: return None return work class rtlsdrBuffer(object): """rtlsdr buffer class read & save RTL-SDR IQ signal Fs : sampling Freq[Hz] Fc : center Freq[Hz] """ def __init__(self, Fs, Fc, N): self.sdr = RtlSdr() self.sdr.sample_rate = Fs self.sdr.center_freq = Fc self.sdr.freq_correction = 60 self.sdr.gain = 'auto' self.N = N self.buffer = np.zeros(self.N, dtype=np.complex128) def read(self): self.buffer = self.sdr.read_samples(self.N) self.sdr.close() def writeSCI(self, fnam, x): self.fnam = fnam np.savetxt(self.fnam, x, fmt='%.18e %+.18ej') def plotPSD(self, x): plt.psd(x, NFFT=1024, Fs=self.sdr.sample_rate/1e6, Fc=self.sdr.center_freq/1e6) plt.xlabel('Frequency [MHz]') plt.ylabel('Relative power [dB]') plt.show() def decimation(self, N): self.decimated = scipy.signal.decimate(self.buffer, N) class fmRadioDemodulator(object): """FM Radio Demodulator class with Audio output Buf: modulatedData Fs : sampling Freq[Hz] Ft : 1st. downSampling target Freq[Hz] """ def __init__(self, Buf, Fs, Ft): self.buf = Buf self.Fs = Fs self.Ft = Ft self.AudioFreq = 44100 self.audioObj = pyaudio.PyAudio() self.audioStream = self.audioObj.open(format=pyaudio.paInt16, channels=1, rate=self.AudioFreq, output=True) self.audioData = None self.d1data = None self.d2data = None self.demodulated = None def playAudio(self): self.d1data = scipy.signal.resample(self.buf, int(len(self.buf)*self.Ft/self.Fs)) self.demodulated = np.angle(self.d1data[1:]*np.conj(self.d1data[:-1])) self.d2data = scipy.signal.resample(self.demodulated, int(len(self.demodulated)*self.AudioFreq/self.Ft)) self.audioData = (self.d2data/math.pi * 32768.0).astype(np.int16) self.audioStream.write(self.audioData) def plotAudio(self): if self.audioData is not None: plt.plot(self.audioData) plt.show() else: print("ERROR: No audio data available.") def writeAudio(self, fb, fext): if self.audioData is not None: FNAME_D1 = fb + "_d1d" + fext FNAME_DM = fb + "_demod" + fext FNAME_D2 = fb + "_d2d" + fext FNAME_A = fb + "_audio" + fext self.fnam = fb self.fext = fext np.savetxt(FNAME_D1, self.d1data, fmt='%.18e %+.18ej') np.savetxt(FNAME_DM, self.demodulated) np.savetxt(FNAME_D2, self.d2data) np.savetxt(FNAME_A, self.audioData) else: print("ERROR: No audio data available.") def main(): """main program. process options """ parser = argparse.ArgumentParser(description=versionSTR) parser.add_argument('--FS', nargs=1, help='sample rate (default=2.1168[MHz])') parser.add_argument('--FC', nargs=1, help='center_freq (defalut=80[MHz])') parser.add_argument('--N', nargs=1, help='number of samples (defalut=256, means 256*1024)') parser.add_argument('--FNAME', nargs=1, help='File name to save (defalut=toScilab.csv)') parser.add_argument('--G', nargs=1, help='select options: psd, decimated, audio(w/-A only)') parser.add_argument('--D', nargs=1, help='decimation factor (defalut=8)') parser.add_argument('-A', dest='AUDIO', help='Play Audio, then save', action='store_true', default=False) parser.add_argument('-V', dest='VERSION', help='Show Version, then exit', action='store_true', default=False) args = parser.parse_args() if args.VERSION: print( versionSTR ) sys.exit(0) Fa = 44100 #sampling Frequency, Audio Output Fs = Fa * 48 #2.1168MHz (OLD:2.048e6) if args.FS is not None: Fs = freqIN(args.FS[0], Fs) Fc = 80e6 if args.FC is not None: Fc = freqIN(args.FC[0], Fc) N = 2560*1024 #10x OLD N if args.N is not None: tmpN = parse2int(args.N[0]) if tmpN is not None: N = tmpN * 1024 FNAME = "toScilab.csv" if args.FNAME is not None: FNAME = args.FNAME[0] fb, fext = os.path.splitext(FNAME) FNAME_D = fb + "_decimated" + fext sdr = rtlsdrBuffer(Fs, Fc, N) sdr.read() sdr.writeSCI(FNAME, sdr.buffer) if args.AUDIO: audioplayer = fmRadioDemodulator(sdr.buffer, Fs, Fa*6) audioplayer.playAudio() audioplayer.writeAudio(fb, fext) if args.D is not None: D = parse2int(args.D[0]) if D is not None: sdr.decimation(D) sdr.writeSCI(FNAME_D, sdr.decimated) if args.G is not None: if args.G[0].startswith('psd'): sdr.plotPSD(sdr.buffer) if args.G[0].startswith('decimated'): sdr.plotPSD(sdr.decimated) if args.G[0].startswith('audio') and args.AUDIO: audioplayer.plotAudio() sys.exit(0) if __name__ == "__main__": main()