forked from vsergeev/luaradio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
frequencytranslator.lua
114 lines (83 loc) · 3.54 KB
/
frequencytranslator.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
---
-- Frequency translate a complex-valued signal by mixing it with $$ e^{j
-- \omega_0 n} $$, where $$ \omega_0 = 2 \pi f_o / f_s $$.
--
-- $$ y[n] = x[n] \; e^{j\omega_0 n} $$
--
-- @category Spectrum Manipulation
-- @block FrequencyTranslatorBlock
-- @tparam number offset Translation offset in Hz
--
-- @signature in:ComplexFloat32 > out:ComplexFloat32
--
-- @usage
-- -- Frequency translate -200 kHz
-- local translator = radio.FrequencyTranslatorBlock(-200e3)
local math = require('math')
local ffi = require('ffi')
local platform = require('radio.core.platform')
local block = require('radio.core.block')
local types = require('radio.types')
local FrequencyTranslatorBlock = block.factory("FrequencyTranslatorBlock")
function FrequencyTranslatorBlock:instantiate(offset)
self.offset = assert(offset, "Missing argument #1 (offset)")
self:add_type_signature({block.Input("in", types.ComplexFloat32)}, {block.Output("out", types.ComplexFloat32)})
end
if platform.features.volk then
function FrequencyTranslatorBlock:initialize()
self.omega = 2*math.pi*(self.offset/self:get_rate())
self.rotation = types.ComplexFloat32(math.cos(self.omega), math.sin(self.omega))
self.phi = types.ComplexFloat32(1, 0)
self.out = types.ComplexFloat32.vector()
end
ffi.cdef[[
void (*volk_32fc_s32fc_x2_rotator_32fc)(complex_float32_t* outVector, const complex_float32_t* inVector, const complex_float32_t phase_inc, complex_float32_t* phase, unsigned int num_points);
]]
local libvolk = platform.libs.volk
function FrequencyTranslatorBlock:process(x)
local out = self.out:resize(x.length)
libvolk.volk_32fc_s32fc_x2_rotator_32fc(out.data, x.data, self.rotation, self.phi, x.length)
return out
end
elseif platform.features.liquid then
ffi.cdef[[
typedef enum { LIQUID_NCO=0, LIQUID_VCO } liquid_ncotype;
typedef struct nco_crcf_s * nco_crcf;
nco_crcf nco_crcf_create(liquid_ncotype _type);
void nco_crcf_destroy(nco_crcf _q);
void nco_crcf_set_frequency(nco_crcf _q, float _f);
void nco_crcf_set_phase(nco_crcf _q, float _phi);
void nco_crcf_mix_block_up(nco_crcf _q, const complex_float32_t *_x, complex_float32_t *_y, unsigned int _N);
]]
local libliquid = platform.libs.liquid
function FrequencyTranslatorBlock:initialize()
self.nco = ffi.gc(libliquid.nco_crcf_create(ffi.C.LIQUID_VCO), libliquid.nco_crcf_destroy)
if self.nco == nil then
error("Creating liquid nco object.")
end
libliquid.nco_crcf_set_frequency(self.nco, 2*math.pi*(self.offset/self:get_rate()))
libliquid.nco_crcf_set_phase(self.nco, 0.0)
self.out = types.ComplexFloat32.vector()
end
function FrequencyTranslatorBlock:process(x)
local out = self.out:resize(x.length)
libliquid.nco_crcf_mix_block_up(self.nco, x.data, out.data, x.length)
return out
end
else
function FrequencyTranslatorBlock:initialize()
self.omega = 2*math.pi*(self.offset/self:get_rate())
self.phase = 0
self.out = types.ComplexFloat32.vector()
end
function FrequencyTranslatorBlock:process(x)
local out = self.out:resize(x.length)
for i = 0, x.length-1 do
out.data[i] = x.data[i] * types.ComplexFloat32(math.cos(self.phase), math.sin(self.phase))
self.phase = self.phase + self.omega
self.phase = (self.phase > 2*math.pi) and (self.phase - 2*math.pi) or self.phase
end
return out
end
end
return FrequencyTranslatorBlock