local radio = require('radio')
if #arg < 2 then
io.stderr:write("Usage: " .. arg[0] .. " <frequency> <sideband>\n")
os.exit(1)
end
assert(arg[2] == "usb" or arg[2] == "lsb", "Sideband should be 'lsb' or 'usb'.")
local frequency = tonumber(arg[1])
local sideband = arg[2]
local tune_offset = -100e3
local bandwidth = 3e3
-- Blocks
--- 1102500 полоса свистка
local source = radio.RtlSdrSource(frequency + tune_offset, 1102500)
-- 1102500/50 = 22050
-- tune_offset на скільки зміщуємо частоту
-- 2*bandwidth це полоса яку ми будемо далі приймати і обробляти
-- 50 is the sample rate of the input signa
-- Свисток стає на частоту прийому 28 мГц
-- 1) 1102500 / 2 = 551 250
-- 28.551,250 і 27,448,750
-- 28 000 000 - 100 000 = 27 900 000 # tune_offset
-- 27 900 000 бере середину , тобто 3 000*2 = 6 000.
-- 27 903 000 і 27,897 полоса має Sample rate 1 102 500 / 50 = 22 050 000 (22 kHz)
local tuner = radio.TunerBlock(tune_offset, 2*bandwidth, 50)
-- тут робимо вибірку або USB або LSB.
local sb_filter = radio.ComplexBandpassFilterBlock(129, (sideband == "lsb") and {0, -bandwidth}
or {0, bandwidth})
--[[
Про число 129.
In digital signal processing, a finite impulse response (FIR) filter is a type of filter that has a finite duration, determined by the number of its filter taps. FIR filters are commonly used in signal processing applications such as filtering and equalization because they provide linear-phase filtering with good control over the filter characteristics.
The number of filter taps determines the length of the filter impulse response, which affects its frequency response and filtering performance. The more taps a filter has, the more precise its frequency response can be shaped. However, increasing the number of taps also increases the computational complexity and latency of the filter.
In the case of the ComplexBandpassFilterBlock in the code snippet, the number of taps is set to 129, which is an odd number. In a symmetric FIR filter, an odd number of taps ensures that the impulse response of the filter is centered around time zero. This centering allows for zero-phase filtering, which means that the phase distortion introduced by the filter is linear and does not vary with frequency. Zero-phase filtering is important in many signal processing applications where phase distortion can affect the accuracy of the results.
--]]
-- беремо ліву або праву частину полоси і пропускаємо через AM детектор
local am_demod = radio.ComplexToRealBlock()
--- Сигнал АМ має полосу 3 кГц і SampleRate 22 050 000.
local af_filter = radio.LowpassFilterBlock(128, bandwidth)
-- bandwidth це полоса сигнлау
--[[
У цьому випадку число 128 вказує на розмір фільтра, який використовується для нижньочастотного фільтрування.
Він задає кількість відліків у фільтрі, які використовуються для обчислення вихідного сигналу фільтра.
Чим більше значення, тим більшу кількість відліків використовує фільтр і тим більш точне його фільтрування.
Однак великі значення також можуть призвести до більшої затримки сигналу.
--]]
local af_gain = radio.AGCBlock('fast')
local sink = os.getenv('DISPLAY') and radio.PulseAudioSink(1) or radio.WAVFileSink('ssb.wav', 1)
-- Plotting sinks
local plot1 = radio.GnuplotSpectrumSink(2048, 'RF Spectrum', {xrange = {-3100,
3100},
yrange = {-120, -40}})
local plot2 = radio.GnuplotSpectrumSink(2048, 'AF Spectrum', {yrange = {-120, -40},
xrange = {0, bandwidth},
update_time = 0.05})
-- Connections
local top = radio.CompositeBlock()
top:connect(source, tuner, sb_filter, am_demod, af_filter, af_gain, sink)
if os.getenv('DISPLAY') then
top:connect(tuner, plot1)
top:connect(af_gain, plot2)
end
top:run()