Audible playback of ultrasound using GNURadio Companion
Inspired by the preamp and hydrophone post yesterday by Mikko Syrjäsuo, I put together some gnuradio scripts for processing infra or ultrasound recordings. There are three different flowgraphs: The first one allows you to playback a recording with a faster or slower speed. The second one allows you to shift signal in frequency by multiplying it with a complex sinusoid up or down in frequency to an audible band. The third one is something similar to what Mikko was describing. It uses a custom python block to compress a wide bandwidth into a more narrow bandwidth by using something called a vocoder (at least that is what I think it is called). I've attached the code.
The audio downconversion script and the vocoder script can also be operated in realtime, by replacing the wav-source block with an audio card block. It sounds very weird talking to a microphone and hearing your own voice shifted to a higher or lower frequency.
For more serious applications, you could also use the USRP N2x0 or USRP1 together with the LFRX daughterboard to record ultrasound signals.
I managed to find nice high frequency (250 kHz) ultrasound recordings of bat sounds on this web site: http://www.batcalls.com/. I have used these for testing. Specifically this wav file.
![]() |
| Flowgraph to adjust the speed of the audio recording, resulting in sped up or slowed down playback of the wav file. |
![]() |
| Audio frequency shifting using mixing and filtering. This allows "mixing" the ultrasound onto an audible frequency band, retaining the temporal characteristics of the signal. |
![]() |
| The vocoder flowgraph. The vocode block is a custom block that I wrote in Python. The code is shown below. |
![]() |
| Bat call signal between 10 and 75 kHz is converted into a 1 to 14 kHz signal. |
The code for the vocoder is shown below:
# Simple vocoder gnuradio block, (c) 2017 Juha Vierinen
#
import numpy as np
from gnuradio import gr
class vocode(gr.sync_block):
"""
docstring for block vocode
"""
def __init__(self, n,n0,n1,dec):
self.buflen=4*n+8192
self.tmp_in = np.zeros(self.buflen,dtype=np.float32) # buffering
self.tmp_out = np.zeros(self.buflen,dtype=np.float32) # buffering
self.fin = np.zeros(n,dtype=np.float32)
self.n = n # fft size
self.n0 = n0 # first bin (mapped to dc freq)
self.n1 = n1 # last bin (mapped to dc+(n1-n0) freq)
self.w=np.zeros(n,dtype=np.float32) # window function
l2=int(n/2)
self.w[0:l2]=np.linspace(0,1.0,num=l2)
self.w[l2:n]=np.linspace(1.0,0.0,num=l2)
# how much do we integrate and decimate spectral components toghether
self.dec = dec
# some buffer indices
self.idx_bufin = 0 # location on input buffer
self.idx_proc = 0 # location on processing buffer
self.idx_out = 0 # location on output buffer
gr.sync_block.__init__(self,
name="vocode",
in_sig=[np.float32],
out_sig=[np.float32])
def work(self, input_items, output_items):
in0 = input_items[0]
out = output_items[0]
L=len(in0)
# insert data into input buffer
self.tmp_in[np.mod(self.idx_bufin+np.arange(L),self.buflen)]=in0
# number of windows we can process
tail = self.idx_bufin+L
n_win = int(np.floor((tail-self.n-self.idx_proc)/(self.n/2)))
# process all available FFT windows (half overlapping)
for i in range(n_win):
# window
i0=self.idx_proc
fin=self.tmp_in[np.mod(i0+np.arange(self.n),self.buflen)]
# compress and shift spectrum
F=np.fft.rfft(self.w*fin)
Fc=np.convolve(F,np.repeat(1.0/float(self.dec),self.dec),mode="same")
idxs=np.arange(self.n0,self.n1,self.dec)
Fc2=np.copy(F) ; Fc2[:]=0.0
Fc2[np.arange(len(idxs))]=Fc[idxs]
self.tmp_out[np.mod(i0+2*self.n+np.arange(self.n),self.buflen)]+=self.w*np.fft.irfft(Fc2)
# empty tail of buffer
self.tmp_out[np.mod(i0-self.n+np.arange(self.n),self.buflen)]=0.0
self.idx_proc+=self.n/2
self.idx_bufin+=L
out[:]=self.tmp_out[np.mod(self.idx_out+np.arange(L),self.buflen)]
self.idx_out+=L
return L







You have posted such a good post. I am very impressed by your work towards your post for sharing such useful information. Thank you.ultrasound Perth
ReplyDeleteAudio Processing Projects is directly relevant to this article because the project focuses on processing ultrasound and infrasound recordings and converting signals into an audible range. The use of frequency shifting, playback-speed adjustment, and bandwidth compression demonstrates practical techniques for analyzing and transforming audio signals.
DeleteDeep Learning Projects for Final Year can be connected to signal-processing applications where advanced computational methods are used to analyze complex audio or sensor data. Working with wide-bandwidth recordings and extracting meaningful signal characteristics can provide useful foundations for developing intelligent audio-processing applications.
DeletePython Online Training is also relevant because the article mentions using a custom Python block within GNU Radio to process the signal and compress its bandwidth. Python provides a practical programming environment for implementing custom signal-processing logic and integrating computational techniques into scientific and engineering workflows.
Deletefake pregnancy ultrasound I think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article.
ReplyDeleteyou give great information for blogger, I learn new information from your article, you are doing a great job. thanks for sharing, keep it up. portable handheld ultrasound
ReplyDelete