SDR
Introduction
Je vais décrire les différentes étapes que je réalise pour tenter de faire fonctionner un système SDR. En effet, même si certain dise que c'est simple, je trouve des plus compliqué ! Suite à de plus amples renseignements arrachés lors des journées du libre à St-Cergue et à l'achat de mon matériel "Pluto" à Vich; je me lance !
PIPO 12
Avec Michel ( HB9DUG ) nous avons installé le logiciel Pothos & Python. Bien que nous ayons réussi à faire fonctionner ma clef USB vis SDR# on est pas arrivé à recevoir le straeming TV de son système. Eh oui !! Facile !!
Mon PC
Suite à ce fiasco, je vais utiliser mon notebook pour tenter l'aventure. Type de mon matériel : Aspire E15 "E5-575G-79G5", Intel Core i7-6500U 2.5GHz, NVIDIA GeForce 940MX. OS window 10.
Installation
J'ai commencé par installé python-2.7.14.amd64. En effet, on m'a dit qu'il valait mieux commencé par le logiciel Python. Ensuite j'ai recherché le logiciel "Pothos" ( pas simple !, c'est en recherchant : pothosware que je l'ai trouvé ! ). J'ai téléchargé PothosSDR-2018.03.12-vc14-x64 et l'ai installé sur ma machine. Atttention lors de l'installation il demande le lien avec Python (bien cocher python 2 !)
Test
Selon information du wiki GNURadio, il nous informe que très certainement des liens n'ont pas été mis à jour et pour le savoir il suffit de lancer le programme GNURadio. Comme prévu j'ai reçu ce message :
Le wiki me demande de lancer un script écrit en python qui se trouve :
https://raw.githubusercontent.com/pothosware/gnuradio-companion-exe/master/GNURadioHelper.py
# SPDX-License-Identifier: BSL-1.0
########################################################################
## Do checks and prepare dependencies for GRC
########################################################################
import os
import sys
import inspect
import tempfile
import subprocess
from ctypes.util import find_library
########################################################################
## Registry/Environment helpers
########################################################################
import ctypes
from ctypes.wintypes import HWND, UINT, WPARAM, LPARAM, LPVOID
LRESULT = LPARAM
import os
import sys
try:
import winreg
unicode = str
except ImportError:
import _winreg as winreg # Python 2.x
class Environment(object):
#path = r'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
#hklm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
path = r'Environment'
hklm = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
key = winreg.OpenKey(hklm, path, 0, winreg.KEY_READ | winreg.KEY_WRITE)
SendMessage = ctypes.windll.user32.SendMessageW
SendMessage.argtypes = HWND, UINT, WPARAM, LPVOID
SendMessage.restype = LRESULT
HWND_BROADCAST = 0xFFFF
WM_SETTINGCHANGE = 0x1A
NO_DEFAULT = type('NO_DEFAULT', (object,), {})()
def get(self, name, default=NO_DEFAULT):
try:
value = winreg.QueryValueEx(self.key, name)[0]
except WindowsError:
if default is self.NO_DEFAULT:
raise ValueError("No such registry key", name)
value = default
return value
def set(self, name, value):
if value:
winreg.SetValueEx(self.key, name, 0, winreg.REG_EXPAND_SZ, value)
else:
winreg.DeleteValue(self.key, name)
self.notify()
def notify(self):
self.SendMessage(
self.HWND_BROADCAST, self.WM_SETTINGCHANGE, 0, u'Environment')
########################################################################
## determine-if-an-executable-or-library-is-32-or-64-bits-on-windows
## https://stackoverflow.com/questions/1345632
########################################################################
import struct
IMAGE_FILE_MACHINE_I386=332
IMAGE_FILE_MACHINE_IA64=512
IMAGE_FILE_MACHINE_AMD64=34404
def getDllMachineType(path):
f=open(path, "rb")
s=f.read(2)
if s!="MZ": raise Exception("%s is not a DLL"%path)
f.seek(60)
s=f.read(4)
header_offset=struct.unpack("<L", s)[0]
f.seek(header_offset+4)
s=f.read(2)
machine=struct.unpack("<H", s)[0]
f.close()
return machine
########################################################################
## Pip helpers
########################################################################
PIP_EXE = os.path.join(os.path.dirname(sys.executable), 'Scripts', 'pip.exe')
def pip_install(arg):
ret = subprocess.call([PIP_EXE, 'install', arg], shell=True)
if ret != 0:
print("Error: pip failed to install %s"%arg)
return -1
########################################################################
## Python checks
########################################################################
def check_python_version():
is_64bits = sys.maxsize > 2**32
if not is_64bits:
raise Exception("requires 64-bit Python")
if sys.version_info.major != 2 or sys.version_info.minor != 7:
raise Exception("requires Python version 2.7")
if not os.path.exists(PIP_EXE):
raise Exception("can't find pip executable %s"%PIP_EXE)
return sys.version
def handle_python_version():
print("Error: Invoke/Reinstall Python2.7 for amd64")
return -1
########################################################################
## GTK checks
########################################################################
def check_gtk_runtime():
gtk_dll_name = "libgtk-win32-2.0-0.dll"
#first check that the installer default is found
installer_default = os.path.join("C:\\Program Files\\GTK2-Runtime Win64\\bin", gtk_dll_name)
if os.path.exists(installer_default): return installer_default
#regular dll search within the path
libgtk = find_library(gtk_dll_name)
if libgtk is None:
raise Exception("failed to locate the GTK+ runtime DLL")
#reject 32-bit versions of this dll
if getDllMachineType(libgtk) != IMAGE_FILE_MACHINE_AMD64:
raise Exception("%s is not AMD64"%libgtk)
return libgtk
def handle_gtk_runtime():
GTK_URL = 'http://downloads.myriadrf.org/binaries/python27_amd64/gtk2-runtime-2.22.1-2014-02-01-ts-win64.exe'
GTK_EXE = os.path.join(tempfile.gettempdir(), 'gtk2-runtime-2.22.1-2014-02-01-ts-win64.exe')
if not os.path.exists(GTK_EXE):
#need requests to download the exe
try: import requests
except: pip_install("requests")
import requests
#download from the url to the destination
r = requests.get(GTK_URL)
with open(GTK_EXE, 'wb') as fd:
for chunk in r.iter_content(1024*1024):
fd.write(chunk)
if not os.path.exists(GTK_EXE):
print("Cant find installer: %s"%GTK_EXE)
print("Failed to download: %s"%GTK_URL)
return -1
print("Running installer: %s"%GTK_EXE)
ret = subprocess.call([GTK_EXE, '/S'], shell=True) #silent install
if ret != 0:
print("The GTK installer failed with exit code %d"%ret)
exit(ret)
print("The GTK installer should have modified the system path")
print("Open a new command window and re-run this script...")
def check_import_gtk():
import gtk
return inspect.getfile(gtk)
def handle_import_gtk():
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/pygtk-2.22.0-cp27-none-win_amd64.whl')
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/pygobject-2.28.6-cp27-none-win_amd64.whl')
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/pycairo_gtk-1.10.0-cp27-none-win_amd64.whl')
########################################################################
## GNU Radio checks
########################################################################
def guess_bin_path():
#was it run from the proper install directory?
path = os.path.abspath(os.path.dirname(__file__))
if os.path.exists(os.path.join(path, "gnuradio-runtime.dll")): return path
#otherwise search the path to find the root
gnuradio_runtime = find_library("gnuradio-runtime.dll")
if gnuradio_runtime: return gnuradio_runtime
def check_gr_runtime():
gnuradio_runtime = find_library("gnuradio-runtime.dll")
if gnuradio_runtime is None:
raise Exception("failed to locate the GNURadio runtime DLL")
return gnuradio_runtime
def handle_gr_runtime():
path = guess_bin_path()
#we dont know where the bin path is, this is probably an installer issue
#print this message and return error so other handlers are not invoked
if path is None:
print("Error: PothosSDR DLLs missing from the system path")
print(" See instructions to 'Add PothosSDR to the system PATH'")
print(" https://github.com/pothosware/PothosSDR/wiki/Tutorial")
return -1
e = Environment()
PATH = e.get('PATH', '')
print("Current PATH: '%s'"%PATH)
if not PATH: PATH = list()
else: PATH = PATH.split(';')
if path not in PATH:
print("Adding %s to the PATH"%path)
PATH.append(path)
e.set('PATH', ';'.join(PATH))
print("")
print("The PATH for the current user has been modified")
print("Open a new command window and re-run this script...")
def check_import_gr():
import gnuradio
from gnuradio import gr
return inspect.getfile(gnuradio)
def handle_import_gr():
binDir = guess_bin_path()
path = os.path.join(os.path.dirname(binDir), 'lib', 'python2.7', 'site-packages')
if not os.path.exists(path): #or use old-style path without python version
path = os.path.join(os.path.dirname(binDir), 'lib', 'site-packages')
path = os.path.normpath(path)
print("Error: GNURadio modules missing from PYTHONPATH")
print("")
print("Current search path:")
for searchPath in sys.path: print(" * %s"%searchPath)
print("")
e = Environment()
PYTHONPATH = e.get('PYTHONPATH', '')
print("Current PYTHONPATH: '%s'"%PYTHONPATH)
if not PYTHONPATH: PYTHONPATH = list()
else: PYTHONPATH = PYTHONPATH.split(';')
if path not in PYTHONPATH:
print("Adding %s to the PYTHONPATH"%path)
PYTHONPATH.append(path)
e.set('PYTHONPATH', ';'.join(PYTHONPATH))
print("")
print("The PYTHONPATH for the current user has been modified")
print("Open a new command window and re-run this script...")
def check_grc_blocks_path():
GRC_BLOCKS_PATH = os.environ.get('GRC_BLOCKS_PATH', '').split(';')[0] #take the first entry
if not GRC_BLOCKS_PATH:
raise Exception("GRC_BLOCKS_PATH is not set")
if not os.path.exists(GRC_BLOCKS_PATH):
raise Exception("GRC_BLOCKS_PATH '%s' does not exist"%GRC_BLOCKS_PATH)
if not os.path.exists(os.path.join(GRC_BLOCKS_PATH, 'options.xml')):
raise Exception("GRC_BLOCKS_PATH '%s' does not contain options.xml"%GRC_BLOCKS_PATH)
return GRC_BLOCKS_PATH
def handle_grc_blocks_path():
binDir = guess_bin_path()
path = os.path.join(os.path.dirname(binDir), 'share', 'gnuradio', 'grc', 'blocks')
path = os.path.normpath(path)
print("Setting the GRC_BLOCKS_PATH to %s"%path)
e = Environment()
e.set('GRC_BLOCKS_PATH', path)
print("")
print("The GRC_BLOCKS_PATH for the current user has been modified")
print("Open a new command window and re-run this script...")
########################################################################
## Other module checks
########################################################################
def check_import_numpy():
import numpy
return inspect.getfile(numpy)
def handle_import_numpy():
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/numpy-1.12.0+mkl-cp27-cp27m-win_amd64.whl')
def check_import_lxml():
import lxml
return inspect.getfile(lxml)
def handle_import_lxml():
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/lxml-3.7.2-cp27-cp27m-win_amd64.whl')
def check_import_cheetah():
import Cheetah
return inspect.getfile(Cheetah)
def handle_import_cheetah():
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/Cheetah-2.4.4-cp27-none-win_amd64.whl')
def check_import_wxpython():
import wx
import wx.glcanvas
return inspect.getfile(wx)
def handle_import_wxpython():
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/wxPython-3.0.2.0-cp27-none-win_amd64.whl')
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/wxPython_common-3.0.2.0-py2-none-any.whl')
def check_import_pyopengl():
import OpenGL
import OpenGL.GL
return inspect.getfile(OpenGL)
def handle_import_pyopengl():
print("Installing PyOpenGL with pip:")
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/PyOpenGL-3.1.1-cp27-cp27m-win_amd64.whl')
pip_install('http://downloads.myriadrf.org/binaries/python27_amd64/PyOpenGL_accelerate-3.1.1-cp27-cp27m-win_amd64.whl')
print(" Done!")
CHECKS = [
#first check gr runtime so we can locate the install based on runtime dll in PATH
("GR_RUNTIME", 'locate GNURadio runtime', check_gr_runtime, handle_gr_runtime),
#gtk runtime is similar check for dlls in the seatch PATH (no python required)
("GTK_RUNTIME", 'locate GTK+ runtime', check_gtk_runtime, handle_gtk_runtime),
#basic python environment and import checks and using pip to install from a URL
("PYVERSION", 'Python version is 2.7', check_python_version, handle_python_version),
("IMPORT_GTK", 'import gtk module', check_import_gtk, handle_import_gtk),
("IMPORT_NUMPY", 'import numpy module', check_import_numpy, handle_import_numpy),
("IMPORT_LXML", 'import lxml module', check_import_lxml, handle_import_lxml),
("IMPORT_CHEETAH", 'import Cheetah module', check_import_cheetah, handle_import_cheetah),
("IMPORT_WX", 'import wx module', check_import_wxpython, handle_import_wxpython),
("IMPORT_OPENGL", 'import OpenGL module', check_import_pyopengl, handle_import_pyopengl),
#final checks for GNU Radio and GRC that set local environment variables
("GRC_BLOCKS", 'GRC blocks path set', check_grc_blocks_path, handle_grc_blocks_path),
("IMPORT_GR", 'import GNURadio module', check_import_gr, handle_import_gr),
]
def main():
print("")
print("="*40)
print("== Runtime and import checks")
print("="*40)
maxLen = max([len(c[1]) for c in CHECKS])
msgs = dict()
statuses = dict()
numFails = 0
numPasses = 0
for key, what, check, handle in CHECKS:
whatStr = "%s...%s"%(what, ' '*(maxLen-len(what)))
try:
msg = check()
statStr = "PASS"
checkPassed = True
numPasses += 1
except Exception as ex:
statStr = "FAIL"
checkPassed = False
msg = str(ex)
numFails += 1
print(" * Check %s %s"%(whatStr, statStr))
msgs[key] = msg
statuses[key] = checkPassed
if numPasses:
print("")
print("="*40)
print("== Checks passed summary")
print("="*40)
for key, what, check, handle in CHECKS:
if statuses[key]: print("%s:\t%s"%(key, msgs[key]))
if numFails == 0:
print("")
print("All checked passed! gnuradio-companion is ready to use.")
return 0
if numFails:
print("")
print("="*40)
print("== Checks failed summary")
print("="*40)
for key, what, check, handle in CHECKS:
if not statuses[key]: print("%s:\t%s"%(key, msgs[key]))
if numFails:
print("")
print("="*40)
print("== Fixing problems")
print("="*40)
for key, what, check, handle in CHECKS:
if not statuses[key]:
print("Handling issues for %s..."%key)
ret = handle()
#exit asap when return code provided
if ret is not None: return ret
print("")
print("Changes made! Please re-run this script in a new terminal.")
if __name__ == '__main__':
#run main with exception handling
ret = None
try: ret = main()
except Exception as ex:
print("Error: %s"%str(ex))
#give time to read message if opened from explorer
#wait for user to press a key
print("")
os.system('pause')
#return the error code from main
if ret is None: ret = 0
exit(ret)
Avec copier - coller, je l'ai sauvé sur mon PC.
J'ouvre le fichier avec "Edit with IDLE", ensuite via "run modul F5" , après avoir installé GTK+ runtime, il m'annonce que je dois réinstallé python 2.7, car j'avais chargé un autre 2.7.14 !
J'ai déinstallé python 2.7 , chargé celui marqué avec amd64 et relancé l'installation !
Ensuite j'ai lancé le script GNURadionHelper.py avec le nouvel IDLE
Comme il me le demande , je relance le script !
Il n'arrive pas a charger GTK et WX !
Je l'ai relancé plus de 5 fois et rien a faire, faut trouver une autre solution !
Je vais tester si je peux importé toutes ces bibliothèques :
Selon le wiki GNURadion il demande d'utiliser "portaudio" dans le fichier config.conf. Je l'ai trouvé en utilisant PowerShell :
comme on le voit le fichier n'existe pas. Donc il faut le créer :
Voilà mon fichier ! Ensuite je l'ai ouvert avec un éditeur (notepad pour moi) et inscrit ce qu'il veulent :
Je test si le prefix PothosSDR existe via PowwerShell :
Je contrôle si elle est chargée : pour ce faire je vais ou se trouve le programme python :
à ce moment audio est en auto et non en portaudio !
Liens
python 2.7 : https://www.python.org/ftp/python/2.7.14/python-2.7.14.amd64.msi
pothos : https://github.com/pothosware/PothosCore/wiki/Downloads
pothos wiki : https://github.com/pothosware/PothosCore/wiki
pothos tutorial : https://github.com/pothosware/PothosFlow/wiki/Tutorial
GNURadio : https://github.com/pothosware/PothosSDR/wiki/GNURadio
GNURadio
Premier pas
https://fr.wikibooks.org/wiki/Introduction_aux_radios_logicielles_avec_GNU_Radio/Prise_en_main
Nous souhaitons ici générer un signal sinusoïdal s de fréquence f réglable, et afficher sa représentation graphique à la manière d'un oscilloscope numérique. Pour cela, il nous faut utiliser les blocs :
Dans le block "Options" , il faut changer QT gui par WX gui
de génération de signaux : Signal Source (de la catégorie Waveform Generators) ;
Dans Frequency , à la place d'une valeure, se trouve une variable f. Ce qui permet via un potentiomètre WX GUI Slider de la régler. Qui se trouve sous GUI Widgets - WX .
On retrouve notre variable f dans ID. Ce block n'est pas câblé.
de visualisation : WX GUI Scope Sink (de Instrumentation >> WX).
Linux
Cette partie explique mon installation sur une distribution Ubuntu 16.04.4. Pour info j'ai créé une clef USB avec cette version avec le logiciel "RUFUS2.18" sous window XP.
Je suis sur une machine Dell Optiplex 780 64 bits. De base une windows 7 est installée, j'ai placé mon Ubuntu dessus.
$ sudo apt update
$ sudo apt install gnuradio
le programme GNURadio ce trouve dans le lanceur ( logo ubuntu ), suffit de faire une recherche avec gnu, et il apparaît. Je le lance :
python 2.7.12 c'est aussi installé !
Je profite pour installer directement GQRX :
~$sudo apt install gqrx-sdr
Ensuite je branche ma clef DVB-t, et je regarde si le programme GQRX la trouve.
je la trouve dans les entrées du programme :
Après scan, je trouve une radio sur 98,2 MHz
GNURadio
En suivant l'excellent document qui se trouve :
http://f0fyf.blogspot.ch/2014/08/recepteur-fm-avec-gnuradio.html
je réalise mon premier programme SDR avec ma clef RTL-SDR.
Normalement on doit pouvoir lancer directement avec le fichier python :
C'est confirmé ! depuis un terminal :
~$python DJTestRadioSDR.py