aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--notebooks/FrameSynchronization.ipynb221
-rwxr-xr-xsrc/gui/gui.py (renamed from src/gui.py)0
-rw-r--r--src/gui/net.py (renamed from src/net.py)0
-rw-r--r--tests/correlator/acgen.datbin5120 -> 0 bytes
-rw-r--r--tests/correlator/acgen.grc188
-rwxr-xr-xtests/correlator/acgen.py120
-rwxr-xr-xtests/correlator/acproc.py57
-rw-r--r--tests/correlator/correlator.grc1475
-rwxr-xr-xtests/correlator/correlator.py445
9 files changed, 1991 insertions, 515 deletions
diff --git a/notebooks/FrameSynchronization.ipynb b/notebooks/FrameSynchronization.ipynb
index e0187b2..911ddd6 100644
--- a/notebooks/FrameSynchronization.ipynb
+++ b/notebooks/FrameSynchronization.ipynb
@@ -8,10 +8,7 @@
"outputs": [],
"source": [
"import numpy as np\n",
- "from numpy_ringbuffer import RingBuffer\n",
- "\n",
- "import matplotlib.pyplot as plt\n",
- "import matplotlib.image as mpimg"
+ "import matplotlib.pyplot as plt"
]
},
{
@@ -23,39 +20,143 @@
]
},
{
+ "cell_type": "markdown",
+ "id": "fc118de2-937b-4157-a5a1-9b7f152bf59b",
+ "metadata": {},
+ "source": [
+ "First we need to create the access code, a barker sequence which has a very good autocorrelation."
+ ]
+ },
+ {
"cell_type": "code",
- "execution_count": 27,
- "id": "025c6919",
- "metadata": {
- "scrolled": false
- },
+ "execution_count": 2,
+ "id": "20dcd173-2889-4e21-9746-3d0a0ab060e8",
+ "metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
- "Header (N=16): [1 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1]\n",
- "Stream (N=80): [0 0 1 1 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 1 1 0 1 1 1\n",
- " 1 1 0 1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 0 1 0 1 1 0 0 1 1 1 0 0 1 1 1 1 1 0\n",
- " 0 1 1 1 0 1]\n",
- "Correlation peak value: 16 at i=47\n"
+ "Access code: 13 bit pattern [1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1] = left padded bytes [31, 53]\n"
]
- },
+ }
+ ],
+ "source": [
+ "ac = [ 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, ]\n",
+ "\n",
+ "ac_pad = [0] * int(8 * np.ceil(len(ac) / 8) - len(ac)) + ac\n",
+ "ac_bytes = list(np.packbits(ac_pad))\n",
+ "\n",
+ "print(f\"Access code: {len(ac)} bit pattern {ac} = left padded bytes {ac_bytes}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5cfd3c9a-d697-4462-bc26-26e82d25cbfd",
+ "metadata": {},
+ "source": [
+ "To correlate with the access code we need its symbols, thus the functions to modulate the access code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "515891a9-dbd2-4088-9a41-b792d878f0fc",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def modulate_qpsk(m):\n",
+ " ampl = np.sqrt(2)\n",
+ " sym = {\n",
+ " 0: ampl * (-1 -1j),\n",
+ " 1: ampl * ( 1 -1j),\n",
+ " 2: ampl * (-1 +1j),\n",
+ " 3: ampl * ( 1 +1j)\n",
+ " }\n",
+ "\n",
+ " return map(lambda k: sym[k], m)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d328e765-e977-4de9-9694-35012193a0aa",
+ "metadata": {},
+ "source": [
+ "### Symbols for QPSK"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "3a4c834f-7012-4e22-b9f3-865527d09c02",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Modulate chunks [0, 1, 3, 3, 0, 3, 1, 1] with QPSK into 8 symbols:\n",
+ "[(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)]\n",
+ "\n",
+ "Reversed complex conjugate list for FIR filter:\n",
+ "[(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)]\n"
+ ]
+ }
+ ],
+ "source": [
+ "# convert into chunks of 2 bits for QPSK\n",
+ "chunks = list(np.matmul(np.array(ac_pad).reshape((-1,2)), np.array([2, 1])))\n",
+ "syms = list(modulate_qpsk(chunks))\n",
+ "print(f\"Modulate chunks {chunks} with QPSK into {len(syms)} symbols:\\n{syms}\\n\")\n",
+ "\n",
+ "fir_syms = list(np.conj(syms[::-1]))\n",
+ "print(f\"Reversed complex conjugate list for FIR filter:\\n{fir_syms}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "d6155b2e-9405-4d20-8c05-72af45575a04",
+ "metadata": {},
+ "outputs": [
{
"data": {
+ "image/png": "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\n",
"text/plain": [
- "<StemContainer object of 3 artists>"
+ "<Figure size 1440x288 with 2 Axes>"
]
},
- "execution_count": 27,
- "metadata": {},
- "output_type": "execute_result"
- },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "fig, (left, right) = plt.subplots(1, 2, figsize = (20, 4))\n",
+ "\n",
+ "left.plot(np.real(syms), \".-\")\n",
+ "left.plot(np.imag(syms), \".-\")\n",
+ "left.set_title(\"Access Code\")\n",
+ "\n",
+ "right.plot(np.real(fir_syms), \".-\")\n",
+ "right.plot(np.imag(fir_syms), \".-\")\n",
+ "right.set_title(\"FIR Filter\")\n",
+ "\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "8163c2e0-0652-43c5-ad32-eaf0e94a638e",
+ "metadata": {},
+ "outputs": [
{
"data": {
- "image/png": "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\n",
+ "image/png": "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\n",
"text/plain": [
- "<Figure size 1800x360 with 1 Axes>"
+ "<Figure size 1440x288 with 2 Axes>"
]
},
"metadata": {
@@ -65,47 +166,57 @@
}
],
"source": [
- "# Create test data\n",
- "seq = np.unpackbits(np.array([0xbe, 0xef], dtype=np.dtype(\"uint8\")))\n",
- "stream = np.concatenate([\n",
- " np.random.randint(low=0, high=2, size=32), seq, np.random.randint(low=0, high=2, size=32)\n",
- "])\n",
- "\n",
- "print(f\"Header (N={len(seq)}): {seq}\")\n",
- "print(f\"Stream (N={len(stream)}): {stream}\")\n",
- "\n",
- "# Create buffers for cross correlation\n",
- "fifo = RingBuffer(len(seq), dtype=np.dtype(\"uint8\"))\n",
- "xcorr = RingBuffer(len(stream) + len(seq), dtype=np.dtype(\"uint8\"))\n",
+ "fig, (left, right) = plt.subplots(1, 2, figsize = (20, 4))\n",
"\n",
- "## fill FIFO with zeros\n",
- "fifo.extend(np.zeros(fifo.maxlen))\n",
+ "left.plot(np.real(syms), np.imag(syms))\n",
+ "left.set_title(\"AC Constellation Diagram\")\n",
"\n",
- "def correlation(v):\n",
- " n = len(seq)\n",
- " d = np.logical_xor(v, seq) # or bitwise_xor, no difference in this case\n",
- " return n - sum(d)\n",
- " \n",
- "for i in range(len(stream) + len(seq) + 1):\n",
- " xcorr.append(correlation(np.array(fifo)))\n",
- " \n",
- " # append stream data\n",
- " # if the stream is finished use zeros\n",
- " fifo.append(stream[i] if i < len(stream) else 0)\n",
+ "xc = np.convolve(fir_syms, syms)\n",
+ "right.plot(np.abs(xc))\n",
+ "right.set_title(\"AC Autocorrelation\")\n",
"\n",
- "# unwrap values\n",
- "xc = np.array(xcorr)\n",
- "# print(f\"Cross correlation: {xc}\")\n",
- "print(f\"Correlation peak value: {np.amax(xc)} at i={np.argmax(xc)}\")\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bc633da5-61b7-4569-adaf-3d019e0f1b17",
+ "metadata": {},
+ "source": [
+ "## Symbols for 16-QAM"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "b56d782d-fcea-4fb9-b0c1-9c3933d5ce6c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def modulate_16qam(m):\n",
+ " sym = {}\n",
+ " return map(lambda k: sym[k] if k in sym.keys() else None, m)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "2fb687aa-0061-4626-bf6b-3ec7d628d739",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# convert into chunks of 4 bits for QPSK\n",
+ "# chunks = list(np.matmul(np.array(ac_pad).reshape((-1,4)), np.array([4, 3, 2, 1])))\n",
+ "# syms = list(modulate_16qam(chunks))\n",
"\n",
- "plt.figure(figsize = (25, 5))\n",
- "plt.stem(xc)"
+ "# print(chunks)\n",
+ "# print(syms)"
]
}
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": "Python 3",
"language": "python",
"name": "python3"
},
@@ -119,7 +230,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.9.2"
+ "version": "3.8.11"
}
},
"nbformat": 4,
diff --git a/src/gui.py b/src/gui/gui.py
index b2cbebb..b2cbebb 100755
--- a/src/gui.py
+++ b/src/gui/gui.py
diff --git a/src/net.py b/src/gui/net.py
index 2c91bb8..2c91bb8 100644
--- a/src/net.py
+++ b/src/gui/net.py
diff --git a/tests/correlator/acgen.dat b/tests/correlator/acgen.dat
deleted file mode 100644
index 537dcc5..0000000
--- a/tests/correlator/acgen.dat
+++ /dev/null
Binary files differ
diff --git a/tests/correlator/acgen.grc b/tests/correlator/acgen.grc
deleted file mode 100644
index ec7c1e8..0000000
--- a/tests/correlator/acgen.grc
+++ /dev/null
@@ -1,188 +0,0 @@
-options:
- parameters:
- author: Naoki Pross
- catch_exceptions: 'True'
- category: '[GRC Hier Blocks]'
- cmake_opt: ''
- comment: ''
- copyright: ''
- description: ''
- gen_cmake: 'On'
- gen_linking: dynamic
- generate_options: no_gui
- hier_block_src_path: '.:'
- id: acgen
- max_nouts: '0'
- output_language: python
- placement: (0,0)
- qt_qss_theme: ''
- realtime_scheduling: ''
- run: 'True'
- run_command: '{python} -u {filename}'
- run_options: run
- sizing_mode: fixed
- thread_safe_setters: ''
- title: Access Code Symbols Generator
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [8, 8]
- rotation: 0
- state: enabled
-
-blocks:
-- name: access_code
- id: variable
- parameters:
- comment: ''
- value: '[ 0xaa, 0xff, 0x0a ]'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [40, 292.0]
- rotation: 0
- state: true
-- name: const
- id: variable_constellation
- parameters:
- comment: ''
- const_points: '[-1-1j, -1+1j, 1+1j, 1-1j]'
- dims: '1'
- normalization: digital.constellation.AMPLITUDE_NORMALIZATION
- precision: '8'
- rot_sym: '4'
- soft_dec_lut: None
- sym_map: '[0, 1, 3, 2]'
- type: qpsk
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [464, 124.0]
- rotation: 0
- state: true
-- name: excess_bw
- id: variable
- parameters:
- comment: ''
- value: '1'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [464, 308.0]
- rotation: 0
- state: true
-- name: samp_rate
- id: variable
- parameters:
- comment: ''
- value: '32000'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [200, 44.0]
- rotation: 0
- state: enabled
-- name: sps
- id: variable
- parameters:
- comment: ''
- value: '4'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [312, 44.0]
- rotation: 0
- state: true
-- name: blocks_file_sink_0
- id: blocks_file_sink
- parameters:
- affinity: ''
- alias: ''
- append: 'False'
- comment: ''
- file: acgen.dat
- type: complex
- unbuffered: 'False'
- vlen: '1'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [752, 204.0]
- rotation: 0
- state: true
-- name: blocks_throttle_0
- id: blocks_throttle
- parameters:
- affinity: ''
- alias: ''
- comment: ''
- ignoretag: 'True'
- maxoutbuf: '0'
- minoutbuf: '0'
- samples_per_second: samp_rate
- type: byte
- vlen: '1'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [264, 220.0]
- rotation: 0
- state: true
-- name: blocks_vector_source_x_0
- id: blocks_vector_source_x
- parameters:
- affinity: ''
- alias: ''
- comment: ''
- maxoutbuf: '0'
- minoutbuf: '0'
- repeat: 'False'
- tags: '[]'
- type: byte
- vector: '[0x00] * 10 + access_code * 10'
- vlen: '1'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [40, 204.0]
- rotation: 0
- state: true
-- name: digital_constellation_modulator_0
- id: digital_constellation_modulator
- parameters:
- affinity: ''
- alias: ''
- comment: ''
- constellation: const
- differential: 'False'
- excess_bw: excess_bw
- log: 'False'
- maxoutbuf: '0'
- minoutbuf: '0'
- samples_per_symbol: sps
- truncate: 'False'
- verbose: 'False'
- states:
- bus_sink: false
- bus_source: false
- bus_structure: null
- coordinate: [464, 196.0]
- rotation: 0
- state: true
-
-connections:
-- [blocks_throttle_0, '0', digital_constellation_modulator_0, '0']
-- [blocks_vector_source_x_0, '0', blocks_throttle_0, '0']
-- [digital_constellation_modulator_0, '0', blocks_file_sink_0, '0']
-
-metadata:
- file_format: 1
diff --git a/tests/correlator/acgen.py b/tests/correlator/acgen.py
deleted file mode 100755
index 5fbdbb4..0000000
--- a/tests/correlator/acgen.py
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-
-#
-# SPDX-License-Identifier: GPL-3.0
-#
-# GNU Radio Python Flow Graph
-# Title: Access Code Symbols Generator
-# Author: Naoki Pross
-# GNU Radio version: 3.9.2.0
-
-from gnuradio import blocks
-from gnuradio import digital
-from gnuradio import gr
-from gnuradio.filter import firdes
-from gnuradio.fft import window
-import sys
-import signal
-from argparse import ArgumentParser
-from gnuradio.eng_arg import eng_float, intx
-from gnuradio import eng_notation
-
-
-
-
-class acgen(gr.top_block):
-
- def __init__(self):
- gr.top_block.__init__(self, "Access Code Symbols Generator", catch_exceptions=True)
-
- ##################################################
- # Variables
- ##################################################
- self.sps = sps = 4
- self.samp_rate = samp_rate = 32000
- self.excess_bw = excess_bw = 1
- self.const = const = digital.constellation_qpsk().base()
- self.access_code = access_code = [ 0xaa, 0xff, 0x0a ]
-
- ##################################################
- # Blocks
- ##################################################
- self.digital_constellation_modulator_0 = digital.generic_mod(
- constellation=const,
- differential=False,
- samples_per_symbol=sps,
- pre_diff_code=True,
- excess_bw=excess_bw,
- verbose=False,
- log=False,
- truncate=False)
- self.blocks_vector_source_x_0 = blocks.vector_source_b([0x00] * 10 + access_code * 10, False, 1, [])
- self.blocks_throttle_0 = blocks.throttle(gr.sizeof_char*1, samp_rate,True)
- self.blocks_file_sink_0 = blocks.file_sink(gr.sizeof_gr_complex*1, 'acgen.dat', False)
- self.blocks_file_sink_0.set_unbuffered(False)
-
-
-
- ##################################################
- # Connections
- ##################################################
- self.connect((self.blocks_throttle_0, 0), (self.digital_constellation_modulator_0, 0))
- self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_throttle_0, 0))
- self.connect((self.digital_constellation_modulator_0, 0), (self.blocks_file_sink_0, 0))
-
-
- def get_sps(self):
- return self.sps
-
- def set_sps(self, sps):
- self.sps = sps
-
- def get_samp_rate(self):
- return self.samp_rate
-
- def set_samp_rate(self, samp_rate):
- self.samp_rate = samp_rate
- self.blocks_throttle_0.set_sample_rate(self.samp_rate)
-
- def get_excess_bw(self):
- return self.excess_bw
-
- def set_excess_bw(self, excess_bw):
- self.excess_bw = excess_bw
-
- def get_const(self):
- return self.const
-
- def set_const(self, const):
- self.const = const
-
- def get_access_code(self):
- return self.access_code
-
- def set_access_code(self, access_code):
- self.access_code = access_code
- self.blocks_vector_source_x_0.set_data([0x00] * 10 + self.access_code * 10, [])
-
-
-
-
-def main(top_block_cls=acgen, options=None):
- tb = top_block_cls()
-
- def sig_handler(sig=None, frame=None):
- tb.stop()
- tb.wait()
-
- sys.exit(0)
-
- signal.signal(signal.SIGINT, sig_handler)
- signal.signal(signal.SIGTERM, sig_handler)
-
- tb.start()
-
- tb.wait()
-
-
-if __name__ == '__main__':
- main()
diff --git a/tests/correlator/acproc.py b/tests/correlator/acproc.py
deleted file mode 100755
index e119520..0000000
--- a/tests/correlator/acproc.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/usr/bin/env python3
-
-import numpy as np
-import matplotlib.pyplot as plt
-import acgen
-
-# Parameters
-# samples per symbol
-sps = 4
-# number of initial bytes (to ignore)
-nzeros = 10
-# length of the access code in bytes
-aclen = 2
-
-# Create samples
-print("Modulating symbols")
-acgen.main()
-
-# Extract one sequence
-print("Extracting symbol sequence")
-
-# raw data
-data = np.fromfile("acgen.dat", dtype=np.complex64)
-plt.plot(data.real)
-plt.plot(data.imag)
-plt.title("Raw Data (time domain)")
-plt.show()
-
-# take only symbols
-symbols = data[1::sps]
-plt.plot(symbols.real, symbols.imag)
-plt.title("Symbols only (constellation)")
-plt.show()
-
-# where ac symbols start, in symbols
-ac_start = nzeros * 8
-ac_end = ac_start + aclen * 8
-
-ac = symbols[ac_start:ac_end]
-
-fig, (ax1, ax2) = plt.subplots(2, 1)
-fig.tight_layout()
-
-ax1.plot(ac.real, ac.imag)
-ax1.set_title("Symbols of Access Code (constellation)")
-
-ax2.plot(ac.real, ".-")
-ax2.plot(ac.imag, ".-")
-ax2.set_title("Symbols of Access Code (time)")
-plt.show()
-
-fir = list(np.conj(ac[::-1]))
-
-# print the symbols
-print(f"Generated {len(ac)} symbols from a {aclen} byte sequence")
-print("Reversed symbols (for FIR filter):")
-print(fir)
diff --git a/tests/correlator/correlator.grc b/tests/correlator/correlator.grc
index cc57e18..9deec54 100644
--- a/tests/correlator/correlator.grc
+++ b/tests/correlator/correlator.grc
@@ -32,6 +32,40 @@ options:
state: enabled
blocks:
+- name: access_code_symbols
+ id: variable
+ parameters:
+ comment: ''
+ value: '[(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j),
+ (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j),
+ (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j),
+ (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)]'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [776, 1140.0]
+ rotation: 0
+ state: enabled
+- name: access_code_symbols_sps
+ id: variable
+ parameters:
+ comment: ''
+ value: '[(1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j),
+ (1.4142197+1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j),
+ (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j),
+ (1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j),
+ (-1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j),
+ (1.4142197-1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j),
+ (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j),
+ (1.4142197+1.4142197j)]'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [224, 132.0]
+ rotation: 0
+ state: enabled
- name: const
id: variable_constellation
parameters:
@@ -48,9 +82,9 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [432, 164.0]
+ coordinate: [592, 484.0]
rotation: 0
- state: true
+ state: enabled
- name: excess_bw
id: variable
parameters:
@@ -60,9 +94,9 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [432, 340.0]
+ coordinate: [496, 484.0]
rotation: 0
- state: true
+ state: enabled
- name: nfilts
id: variable
parameters:
@@ -72,9 +106,24 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [696, 356.0]
+ coordinate: [224, 988.0]
rotation: 0
- state: true
+ state: enabled
+- name: revconj_access_code_symbols
+ id: variable
+ parameters:
+ comment: ''
+ value: '[(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j),
+ (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j),
+ (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j),
+ (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)]'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [48, 564.0]
+ rotation: 0
+ state: enabled
- name: rrc_taps
id: variable
parameters:
@@ -84,9 +133,9 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [768, 356.0]
+ coordinate: [304, 988.0]
rotation: 0
- state: true
+ state: enabled
- name: samp_rate
id: variable
parameters:
@@ -96,7 +145,7 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [256, 52.0]
+ coordinate: [8, 116.0]
rotation: 0
state: enabled
- name: sps
@@ -108,9 +157,21 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [352, 52.0]
+ coordinate: [104, 116.0]
rotation: 0
- state: true
+ state: enabled
+- name: testvec
+ id: variable
+ parameters:
+ comment: ''
+ value: '[31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3]'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [48, 492.0]
+ rotation: 0
+ state: enabled
- name: timing_loop_bw
id: variable
parameters:
@@ -120,11 +181,31 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [696, 420.0]
+ coordinate: [224, 1068.0]
rotation: 0
- state: true
-- name: blocks_complex_to_mag_0
- id: blocks_complex_to_mag
+ state: enabled
+- name: blocks_burst_tagger_0
+ id: blocks_burst_tagger
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ false_key: nothing
+ false_value: '0'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ true_key: peak
+ true_value: 'True'
+ type: float
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [944, 1580.0]
+ rotation: 0
+ state: disabled
+- name: blocks_char_to_short_0
+ id: blocks_char_to_short
parameters:
affinity: ''
alias: ''
@@ -136,9 +217,93 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [1584, 80.0]
+ coordinate: [752, 1624.0]
rotation: 0
- state: true
+ state: disabled
+- name: blocks_complex_to_magphase_0
+ id: blocks_complex_to_magphase
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1048, 696.0]
+ rotation: 0
+ state: enabled
+- name: blocks_complex_to_magphase_0_0
+ id: blocks_complex_to_magphase
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1048, 1104.0]
+ rotation: 0
+ state: enabled
+- name: blocks_complex_to_magphase_0_1
+ id: blocks_complex_to_magphase
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [256, 1592.0]
+ rotation: 0
+ state: disabled
+- name: blocks_multiply_const_vxx_0
+ id: blocks_multiply_const_vxx
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ const: 180 / 3.141592653589793
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1288, 724.0]
+ rotation: 0
+ state: enabled
+- name: blocks_multiply_const_vxx_0_0
+ id: blocks_multiply_const_vxx
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ const: 180 / 3.141592653589793
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1336, 1180.0]
+ rotation: 0
+ state: disabled
- name: blocks_null_sink_0
id: blocks_null_sink
parameters:
@@ -153,9 +318,118 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [1528, 216.0]
+ coordinate: [1504, 1696.0]
+ rotation: 0
+ state: disabled
+- name: blocks_null_sink_2
+ id: blocks_null_sink
+ parameters:
+ affinity: ''
+ alias: ''
+ bus_structure_sink: '[[0,],]'
+ comment: ''
+ num_inputs: '1'
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [528, 1720.0]
+ rotation: 0
+ state: disabled
+- name: blocks_null_sink_3
+ id: blocks_null_sink
+ parameters:
+ affinity: ''
+ alias: ''
+ bus_structure_sink: '[[0,],]'
+ comment: ''
+ num_inputs: '1'
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1336, 1232.0]
rotation: 0
state: true
+- name: blocks_null_source_0
+ id: blocks_null_source
+ parameters:
+ affinity: ''
+ alias: ''
+ bus_structure_source: '[[0,],]'
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_outputs: '1'
+ type: byte
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [96, 344.0]
+ rotation: 0
+ state: enabled
+- name: blocks_peak_detector2_fb_0
+ id: blocks_peak_detector2_fb
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha: '0.001'
+ comment: ''
+ look_ahead: '1000'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ threshold_factor_rise: '7'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [528, 1620.0]
+ rotation: 0
+ state: disabled
+- name: blocks_stream_mux_0
+ id: blocks_stream_mux
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ lengths: '[10, len(testvec)]'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_inputs: '2'
+ type: byte
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [288, 392.0]
+ rotation: 0
+ state: enabled
+- name: blocks_stream_mux_1
+ id: blocks_stream_mux
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ lengths: '[len(access_code_symbols_sps), sps * (len(testvec) + 15)]'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_inputs: '2'
+ type: complex
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [776, 280.0]
+ rotation: 0
+ state: disabled
- name: blocks_throttle_0
id: blocks_throttle
parameters:
@@ -166,15 +440,15 @@ blocks:
maxoutbuf: '0'
minoutbuf: '0'
samples_per_second: samp_rate
- type: byte
+ type: complex
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [248, 260.0]
+ coordinate: [1272, 404.0]
rotation: 0
- state: true
+ state: enabled
- name: blocks_vector_source_x_0
id: blocks_vector_source_x
parameters:
@@ -186,15 +460,56 @@ blocks:
repeat: 'False'
tags: '[]'
type: byte
- vector: ([0x00] * 10 + [0xaa, 0xff, 0x0a] + [0x00] * 10) * 20
+ vector: testvec * 1600
vlen: '1'
states:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [16, 244.0]
+ coordinate: [48, 404.0]
rotation: 0
- state: true
+ state: enabled
+- name: blocks_vector_source_x_1
+ id: blocks_vector_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ repeat: 'True'
+ tags: '[]'
+ type: complex
+ vector: access_code_symbols_sps
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [224, 204.0]
+ rotation: 0
+ state: disabled
+- name: channels_channel_model_0
+ id: channels_channel_model
+ parameters:
+ affinity: ''
+ alias: ''
+ block_tags: 'False'
+ comment: ''
+ epsilon: '1.0'
+ freq_offset: '0.000001'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ noise_voltage: '0.2'
+ seed: '243'
+ taps: -1.4 + .4j
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [992, 364.0]
+ rotation: 0
+ state: enabled
- name: digital_cma_equalizer_cc_0
id: digital_cma_equalizer_cc
parameters:
@@ -211,7 +526,7 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [992, 188.0]
+ coordinate: [528, 812.0]
rotation: 0
state: enabled
- name: digital_constellation_decoder_cb_0
@@ -227,9 +542,9 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [1264, 212.0]
+ coordinate: [1232, 1692.0]
rotation: 0
- state: true
+ state: disabled
- name: digital_constellation_modulator_0
id: digital_constellation_modulator
parameters:
@@ -249,9 +564,29 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [432, 236.0]
+ coordinate: [496, 380.0]
rotation: 0
- state: true
+ state: enabled
+- name: digital_corr_est_cc_0
+ id: digital_corr_est_cc
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ mark_delay: '0'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ sps: '1'
+ symbols: access_code_symbols
+ threshold: '.8'
+ threshold_method: digital.THRESHOLD_DYNAMIC
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [776, 1020.0]
+ rotation: 0
+ state: enabled
- name: digital_pfb_clock_sync_xxx_0
id: digital_pfb_clock_sync_xxx
parameters:
@@ -272,9 +607,9 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [696, 212.0]
+ coordinate: [224, 836.0]
rotation: 0
- state: true
+ state: enabled
- name: fir_filter_xxx_1
id: fir_filter_xxx
parameters:
@@ -285,19 +620,339 @@ blocks:
maxoutbuf: '0'
minoutbuf: '0'
samp_delay: '0'
- taps: '[(-1.4142197+1.4142197j), (-1.4142197+1.4142197j), (1.4142197-1.4142197j),
- (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (-1.4142197-1.4142197j),
- (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j),
- (-1.4142197-1.4142197j), (-1.4142197+1.4142197j), (-1.4142197+1.4142197j), (1.4142197-1.4142197j),
- (1.4142197-1.4142197j)]'
+ taps: revconj_access_code_symbols
type: ccc
states:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [1328, 68.0]
+ coordinate: [776, 828.0]
+ rotation: 0
+ state: enabled
+- name: high_pass_filter_0
+ id: high_pass_filter
+ parameters:
+ affinity: ''
+ alias: ''
+ beta: '6.76'
+ comment: ''
+ cutoff_freq: 5e3
+ decim: '1'
+ gain: '1'
+ interp: '1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samp_rate: samp_rate
+ type: fir_filter_fff
+ width: '.7'
+ win: window.WIN_HAMMING
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [528, 1420.0]
+ rotation: 0
+ state: disabled
+- name: low_pass_filter_0
+ id: low_pass_filter
+ parameters:
+ affinity: ''
+ alias: ''
+ beta: '6.76'
+ comment: ''
+ cutoff_freq: 7e3
+ decim: '1'
+ gain: '1'
+ interp: '1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samp_rate: samp_rate
+ type: fir_filter_fff
+ width: '.8'
+ win: window.WIN_HAMMING
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [528, 1252.0]
+ rotation: 0
+ state: disabled
+- name: qtgui_const_sink_x_0
+ id: qtgui_const_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ axislabels: 'True'
+ color1: '"blue"'
+ color10: '"red"'
+ color2: '"red"'
+ color3: '"red"'
+ color4: '"red"'
+ color5: '"red"'
+ color6: '"red"'
+ color7: '"red"'
+ color8: '"red"'
+ color9: '"red"'
+ comment: ''
+ grid: 'False'
+ gui_hint: 0,1,2,1
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ marker1: '0'
+ marker10: '0'
+ marker2: '0'
+ marker3: '0'
+ marker4: '0'
+ marker5: '0'
+ marker6: '0'
+ marker7: '0'
+ marker8: '0'
+ marker9: '0'
+ name: '"Equalized Signal"'
+ nconnections: '1'
+ size: '1024'
+ style1: '0'
+ style10: '0'
+ style2: '0'
+ style3: '0'
+ style4: '0'
+ style5: '0'
+ style6: '0'
+ style7: '0'
+ style8: '0'
+ style9: '0'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ xmax: '2'
+ xmin: '-2'
+ ymax: '2'
+ ymin: '-2'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [776, 716.0]
+ rotation: 0
+ state: enabled
+- name: qtgui_const_sink_x_1
+ id: qtgui_const_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '.5'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: '"blue"'
+ color10: '"red"'
+ color2: '"red"'
+ color3: '"red"'
+ color4: '"red"'
+ color5: '"red"'
+ color6: '"red"'
+ color7: '"red"'
+ color8: '"red"'
+ color9: '"red"'
+ comment: ''
+ grid: 'True'
+ gui_hint: 2,1,2,1
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ marker1: '9'
+ marker10: '0'
+ marker2: '0'
+ marker3: '0'
+ marker4: '0'
+ marker5: '0'
+ marker6: '0'
+ marker7: '0'
+ marker8: '0'
+ marker9: '0'
+ name: '"Cross Correlation"'
+ nconnections: '1'
+ size: '1024'
+ style1: '2'
+ style10: '0'
+ style2: '0'
+ style3: '0'
+ style4: '0'
+ style5: '0'
+ style6: '0'
+ style7: '0'
+ style8: '0'
+ style9: '0'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ xmax: '2'
+ xmin: '-2'
+ ymax: '2'
+ ymin: '-2'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1048, 612.0]
rotation: 0
state: enabled
+- name: qtgui_const_sink_x_2
+ id: qtgui_const_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'False'
+ axislabels: 'True'
+ color1: '"blue"'
+ color10: '"red"'
+ color2: '"red"'
+ color3: '"red"'
+ color4: '"red"'
+ color5: '"red"'
+ color6: '"red"'
+ color7: '"red"'
+ color8: '"red"'
+ color9: '"red"'
+ comment: ''
+ grid: 'False'
+ gui_hint: '2,1,2,1 '
+ label1: ''
+ label10: ''
+ label2: ''
+ label3: ''
+ label4: ''
+ label5: ''
+ label6: ''
+ label7: ''
+ label8: ''
+ label9: ''
+ legend: 'True'
+ marker1: '0'
+ marker10: '0'
+ marker2: '0'
+ marker3: '0'
+ marker4: '0'
+ marker5: '0'
+ marker6: '0'
+ marker7: '0'
+ marker8: '0'
+ marker9: '0'
+ name: '"Phase Correction"'
+ nconnections: '1'
+ size: '1024'
+ style1: '0'
+ style10: '0'
+ style2: '0'
+ style3: '0'
+ style4: '0'
+ style5: '0'
+ style6: '0'
+ style7: '0'
+ style8: '0'
+ style9: '0'
+ tr_chan: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ xmax: '2'
+ xmin: '-2'
+ ymax: '2'
+ ymin: '-2'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1248, 1588.0]
+ rotation: 0
+ state: disabled
- name: qtgui_time_sink_x_0
id: qtgui_time_sink_x
parameters:
@@ -313,7 +968,7 @@ blocks:
alpha7: '1.0'
alpha8: '1.0'
alpha9: '1.0'
- autoscale: 'False'
+ autoscale: 'True'
axislabels: 'True'
color1: blue
color10: dark blue
@@ -326,7 +981,104 @@ blocks:
color8: dark red
color9: dark green
comment: ''
- ctrlpanel: 'True'
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'False'
+ gui_hint: 2,0,1,1
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '-1'
+ marker10: '-1'
+ marker2: '-1'
+ marker3: '-1'
+ marker4: '-1'
+ marker5: '-1'
+ marker6: '-1'
+ marker7: '-1'
+ marker8: '-1'
+ marker9: '-1'
+ name: '""'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: float
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: XC Magnitude
+ ymax: '20'
+ ymin: '0'
+ yunit: '""'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1320, 604.0]
+ rotation: 0
+ state: enabled
+- name: qtgui_time_sink_x_0_0
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: blue
+ color10: dark blue
+ color2: red
+ color3: green
+ color4: black
+ color5: cyan
+ color6: magenta
+ color7: yellow
+ color8: dark red
+ color9: dark green
+ comment: ''
+ ctrlpanel: 'False'
entags: 'True'
grid: 'False'
gui_hint: ''
@@ -384,17 +1136,114 @@ blocks:
width7: '1'
width8: '1'
width9: '1'
- ylabel: Amplitude
- ymax: '50'
+ ylabel: XC Magnitude
+ ymax: '20'
ymin: '0'
yunit: '""'
states:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [1792, 60.0]
+ coordinate: [1336, 1084.0]
rotation: 0
- state: true
+ state: enabled
+- name: qtgui_time_sink_x_0_0_0
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: blue
+ color10: dark blue
+ color2: red
+ color3: green
+ color4: black
+ color5: cyan
+ color6: magenta
+ color7: yellow
+ color8: dark red
+ color9: dark green
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '-1'
+ marker10: '-1'
+ marker2: '-1'
+ marker3: '-1'
+ marker4: '-1'
+ marker5: '-1'
+ marker6: '-1'
+ marker7: '-1'
+ marker8: '-1'
+ marker9: '-1'
+ name: '""'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: XC Magnitude
+ ymax: '2'
+ ymin: '-2'
+ yunit: '""'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1048, 1020.0]
+ rotation: 0
+ state: enabled
- name: qtgui_time_sink_x_1
id: qtgui_time_sink_x
parameters:
@@ -423,7 +1272,7 @@ blocks:
color8: dark red
color9: dark green
comment: ''
- ctrlpanel: 'True'
+ ctrlpanel: 'False'
entags: 'True'
grid: 'False'
gui_hint: ''
@@ -469,7 +1318,7 @@ blocks:
tr_mode: qtgui.TRIG_MODE_FREE
tr_slope: qtgui.TRIG_SLOPE_POS
tr_tag: '""'
- type: complex
+ type: float
update_time: '0.10'
width1: '1'
width10: '1'
@@ -482,6 +1331,200 @@ blocks:
width8: '1'
width9: '1'
ylabel: Amplitude
+ ymax: '20'
+ ymin: '-5'
+ yunit: '""'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [784, 1452.0]
+ rotation: 0
+ state: disabled
+- name: qtgui_time_sink_x_1_0
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: blue
+ color10: dark blue
+ color2: red
+ color3: green
+ color4: black
+ color5: cyan
+ color6: magenta
+ color7: yellow
+ color8: dark red
+ color9: dark green
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'False'
+ gui_hint: 0,0,1,1
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '-1'
+ marker10: '-1'
+ marker2: '-1'
+ marker3: '-1'
+ marker4: '-1'
+ marker5: '-1'
+ marker6: '-1'
+ marker7: '-1'
+ marker8: '-1'
+ marker9: '-1'
+ name: '""'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: Modulated
+ ymax: '2'
+ ymin: '-2'
+ yunit: '""'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [808, 452.0]
+ rotation: 0
+ state: enabled
+- name: qtgui_time_sink_x_1_1
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: blue
+ color10: dark blue
+ color2: red
+ color3: green
+ color4: black
+ color5: cyan
+ color6: magenta
+ color7: yellow
+ color8: dark red
+ color9: dark green
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'True'
+ gui_hint: 1,0,1,1
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '-1'
+ marker10: '-1'
+ marker2: '-1'
+ marker3: '-1'
+ marker4: '-1'
+ marker5: '-1'
+ marker6: '-1'
+ marker7: '-1'
+ marker8: '-1'
+ marker9: '-1'
+ name: '""'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: complex
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: Equalized
ymax: '2'
ymin: '-2'
yunit: '""'
@@ -489,21 +1532,347 @@ blocks:
bus_sink: false
bus_source: false
bus_structure: null
- coordinate: [696, 108.0]
+ coordinate: [776, 612.0]
+ rotation: 0
+ state: enabled
+- name: qtgui_time_sink_x_2
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: blue
+ color10: dark blue
+ color2: red
+ color3: green
+ color4: black
+ color5: cyan
+ color6: magenta
+ color7: yellow
+ color8: dark red
+ color9: dark green
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'False'
+ gui_hint: 3,0,1,1
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '-1'
+ marker10: '-1'
+ marker2: '-1'
+ marker3: '-1'
+ marker4: '-1'
+ marker5: '-1'
+ marker6: '-1'
+ marker7: '-1'
+ marker8: '-1'
+ marker9: '-1'
+ name: '""'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: float
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: XC Phase
+ ymax: '1'
+ ymin: '-1'
+ yunit: '""'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1480, 708.0]
+ rotation: 0
+ state: enabled
+- name: qtgui_time_sink_x_2_0
+ id: qtgui_time_sink_x
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha1: '1.0'
+ alpha10: '1.0'
+ alpha2: '1.0'
+ alpha3: '1.0'
+ alpha4: '1.0'
+ alpha5: '1.0'
+ alpha6: '1.0'
+ alpha7: '1.0'
+ alpha8: '1.0'
+ alpha9: '1.0'
+ autoscale: 'True'
+ axislabels: 'True'
+ color1: blue
+ color10: dark blue
+ color2: red
+ color3: green
+ color4: black
+ color5: cyan
+ color6: magenta
+ color7: yellow
+ color8: dark red
+ color9: dark green
+ comment: ''
+ ctrlpanel: 'False'
+ entags: 'True'
+ grid: 'False'
+ gui_hint: ''
+ label1: Signal 1
+ label10: Signal 10
+ label2: Signal 2
+ label3: Signal 3
+ label4: Signal 4
+ label5: Signal 5
+ label6: Signal 6
+ label7: Signal 7
+ label8: Signal 8
+ label9: Signal 9
+ legend: 'True'
+ marker1: '-1'
+ marker10: '-1'
+ marker2: '-1'
+ marker3: '-1'
+ marker4: '-1'
+ marker5: '-1'
+ marker6: '-1'
+ marker7: '-1'
+ marker8: '-1'
+ marker9: '-1'
+ name: '""'
+ nconnections: '1'
+ size: '1024'
+ srate: samp_rate
+ stemplot: 'False'
+ style1: '1'
+ style10: '1'
+ style2: '1'
+ style3: '1'
+ style4: '1'
+ style5: '1'
+ style6: '1'
+ style7: '1'
+ style8: '1'
+ style9: '1'
+ tr_chan: '0'
+ tr_delay: '0'
+ tr_level: '0.0'
+ tr_mode: qtgui.TRIG_MODE_FREE
+ tr_slope: qtgui.TRIG_SLOPE_POS
+ tr_tag: '""'
+ type: float
+ update_time: '0.10'
+ width1: '1'
+ width10: '1'
+ width2: '1'
+ width3: '1'
+ width4: '1'
+ width5: '1'
+ width6: '1'
+ width7: '1'
+ width8: '1'
+ width9: '1'
+ ylabel: XC Phase
+ ymax: '1'
+ ymin: '-1'
+ yunit: '""'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1512, 1164.0]
+ rotation: 0
+ state: disabled
+- name: root_raised_cosine_filter_0
+ id: root_raised_cosine_filter
+ parameters:
+ affinity: ''
+ alias: ''
+ alpha: excess_bw
+ comment: ''
+ decim: '1'
+ gain: '2'
+ interp: '1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ ntaps: 11*samp_rate
+ samp_rate: samp_rate
+ sym_rate: sps * samp_rate
+ type: fir_filter_ccf
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [496, 180.0]
+ rotation: 0
+ state: disabled
+- name: virtual_sink_0
+ id: virtual_sink
+ parameters:
+ alias: ''
+ comment: ''
+ stream_id: envelope
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1480, 404.0]
+ rotation: 0
+ state: enabled
+- name: virtual_sink_1
+ id: virtual_sink
+ parameters:
+ alias: ''
+ comment: ''
+ stream_id: symbols
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [776, 916.0]
rotation: 0
state: true
+- name: virtual_sink_2
+ id: virtual_sink
+ parameters:
+ alias: ''
+ comment: ''
+ stream_id: xcorrelation
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1080, 836.0]
+ rotation: 0
+ state: true
+- name: virtual_source_0
+ id: virtual_source
+ parameters:
+ alias: ''
+ comment: ''
+ stream_id: envelope
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [32, 884.0]
+ rotation: 0
+ state: enabled
+- name: virtual_source_2
+ id: virtual_source
+ parameters:
+ alias: ''
+ comment: ''
+ stream_id: symbols
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [32, 1716.0]
+ rotation: 0
+ state: disabled
+- name: virtual_source_3
+ id: virtual_source
+ parameters:
+ alias: ''
+ comment: ''
+ stream_id: xcorrelation
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [32, 1604.0]
+ rotation: 0
+ state: disabled
connections:
-- [blocks_complex_to_mag_0, '0', qtgui_time_sink_x_0, '0']
-- [blocks_throttle_0, '0', digital_constellation_modulator_0, '0']
-- [blocks_vector_source_x_0, '0', blocks_throttle_0, '0']
-- [digital_cma_equalizer_cc_0, '0', digital_constellation_decoder_cb_0, '0']
+- [blocks_char_to_short_0, '0', blocks_burst_tagger_0, '1']
+- [blocks_complex_to_magphase_0, '0', qtgui_time_sink_x_0, '0']
+- [blocks_complex_to_magphase_0, '1', blocks_multiply_const_vxx_0, '0']
+- [blocks_complex_to_magphase_0_0, '0', qtgui_time_sink_x_0_0, '0']
+- [blocks_complex_to_magphase_0_0, '1', blocks_multiply_const_vxx_0_0, '0']
+- [blocks_complex_to_magphase_0_0, '1', blocks_null_sink_3, '0']
+- [blocks_complex_to_magphase_0_1, '0', blocks_burst_tagger_0, '0']
+- [blocks_complex_to_magphase_0_1, '0', blocks_peak_detector2_fb_0, '0']
+- [blocks_complex_to_magphase_0_1, '0', high_pass_filter_0, '0']
+- [blocks_complex_to_magphase_0_1, '0', low_pass_filter_0, '0']
+- [blocks_complex_to_magphase_0_1, '1', blocks_null_sink_2, '0']
+- [blocks_multiply_const_vxx_0, '0', qtgui_time_sink_x_2, '0']
+- [blocks_multiply_const_vxx_0_0, '0', qtgui_time_sink_x_2_0, '0']
+- [blocks_null_source_0, '0', blocks_stream_mux_0, '0']
+- [blocks_peak_detector2_fb_0, '0', blocks_char_to_short_0, '0']
+- [blocks_stream_mux_0, '0', digital_constellation_modulator_0, '0']
+- [blocks_stream_mux_1, '0', channels_channel_model_0, '0']
+- [blocks_throttle_0, '0', virtual_sink_0, '0']
+- [blocks_vector_source_x_0, '0', blocks_stream_mux_0, '1']
+- [blocks_vector_source_x_1, '0', root_raised_cosine_filter_0, '0']
+- [channels_channel_model_0, '0', blocks_throttle_0, '0']
+- [digital_cma_equalizer_cc_0, '0', digital_corr_est_cc_0, '0']
- [digital_cma_equalizer_cc_0, '0', fir_filter_xxx_1, '0']
+- [digital_cma_equalizer_cc_0, '0', qtgui_const_sink_x_0, '0']
+- [digital_cma_equalizer_cc_0, '0', qtgui_time_sink_x_1_1, '0']
+- [digital_cma_equalizer_cc_0, '0', virtual_sink_1, '0']
- [digital_constellation_decoder_cb_0, '0', blocks_null_sink_0, '0']
-- [digital_constellation_modulator_0, '0', digital_pfb_clock_sync_xxx_0, '0']
-- [digital_constellation_modulator_0, '0', qtgui_time_sink_x_1, '0']
+- [digital_constellation_modulator_0, '0', blocks_stream_mux_1, '1']
+- [digital_constellation_modulator_0, '0', channels_channel_model_0, '0']
+- [digital_constellation_modulator_0, '0', qtgui_time_sink_x_1_0, '0']
+- [digital_corr_est_cc_0, '0', qtgui_time_sink_x_0_0_0, '0']
+- [digital_corr_est_cc_0, '1', blocks_complex_to_magphase_0_0, '0']
- [digital_pfb_clock_sync_xxx_0, '0', digital_cma_equalizer_cc_0, '0']
-- [fir_filter_xxx_1, '0', blocks_complex_to_mag_0, '0']
+- [fir_filter_xxx_1, '0', blocks_complex_to_magphase_0, '0']
+- [fir_filter_xxx_1, '0', qtgui_const_sink_x_1, '0']
+- [fir_filter_xxx_1, '0', virtual_sink_2, '0']
+- [high_pass_filter_0, '0', qtgui_time_sink_x_1, '0']
+- [low_pass_filter_0, '0', qtgui_time_sink_x_1, '0']
+- [root_raised_cosine_filter_0, '0', blocks_stream_mux_1, '0']
+- [virtual_source_0, '0', digital_pfb_clock_sync_xxx_0, '0']
+- [virtual_source_3, '0', blocks_complex_to_magphase_0_1, '0']
metadata:
file_format: 1
diff --git a/tests/correlator/correlator.py b/tests/correlator/correlator.py
index 79fa3f8..376d061 100755
--- a/tests/correlator/correlator.py
+++ b/tests/correlator/correlator.py
@@ -26,6 +26,7 @@ from gnuradio import qtgui
from gnuradio.filter import firdes
import sip
from gnuradio import blocks
+from gnuradio import channels
from gnuradio import digital
from gnuradio import filter
from gnuradio import gr
@@ -80,32 +81,143 @@ class correlator(gr.top_block, Qt.QWidget):
self.nfilts = nfilts = 32
self.excess_bw = excess_bw = .35
self.timing_loop_bw = timing_loop_bw = 2 * 3.141592653589793 / 100
+ self.testvec = testvec = [31, 53] + [0x12, 0xe3, 0x9b, 0xee, 0x84, 0x23, 0x41, 0xf3]
self.samp_rate = samp_rate = 32000
self.rrc_taps = rrc_taps = firdes.root_raised_cosine(nfilts, nfilts, 1.0/float(sps), excess_bw, 45*nfilts)
+ self.revconj_access_code_symbols = revconj_access_code_symbols = [(1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951+1.4142135623730951j)]
self.const = const = digital.constellation_qpsk().base()
+ self.access_code_symbols_sps = access_code_symbols_sps = [(1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j), (1.4142197+1.4142197j)]
+ self.access_code_symbols = access_code_symbols = [(-1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (-1.4142135623730951-1.4142135623730951j), (1.4142135623730951+1.4142135623730951j), (1.4142135623730951-1.4142135623730951j), (1.4142135623730951-1.4142135623730951j)]
##################################################
# Blocks
##################################################
- self.qtgui_time_sink_x_1 = qtgui.time_sink_c(
+ self.qtgui_time_sink_x_2 = qtgui.time_sink_f(
1024, #size
samp_rate, #samp_rate
"", #name
1, #number of inputs
None # parent
)
- self.qtgui_time_sink_x_1.set_update_time(0.10)
- self.qtgui_time_sink_x_1.set_y_axis(-2, 2)
+ self.qtgui_time_sink_x_2.set_update_time(0.10)
+ self.qtgui_time_sink_x_2.set_y_axis(-1, 1)
- self.qtgui_time_sink_x_1.set_y_label('Amplitude', "")
+ self.qtgui_time_sink_x_2.set_y_label('XC Phase', "")
- self.qtgui_time_sink_x_1.enable_tags(True)
- self.qtgui_time_sink_x_1.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
- self.qtgui_time_sink_x_1.enable_autoscale(False)
- self.qtgui_time_sink_x_1.enable_grid(False)
- self.qtgui_time_sink_x_1.enable_axis_labels(True)
- self.qtgui_time_sink_x_1.enable_control_panel(True)
- self.qtgui_time_sink_x_1.enable_stem_plot(False)
+ self.qtgui_time_sink_x_2.enable_tags(True)
+ self.qtgui_time_sink_x_2.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
+ self.qtgui_time_sink_x_2.enable_autoscale(True)
+ self.qtgui_time_sink_x_2.enable_grid(False)
+ self.qtgui_time_sink_x_2.enable_axis_labels(True)
+ self.qtgui_time_sink_x_2.enable_control_panel(False)
+ self.qtgui_time_sink_x_2.enable_stem_plot(False)
+
+
+ labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5',
+ 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10']
+ widths = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ colors = ['blue', 'red', 'green', 'black', 'cyan',
+ 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue']
+ alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0]
+ styles = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ markers = [-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1]
+
+
+ for i in range(1):
+ if len(labels[i]) == 0:
+ self.qtgui_time_sink_x_2.set_line_label(i, "Data {0}".format(i))
+ else:
+ self.qtgui_time_sink_x_2.set_line_label(i, labels[i])
+ self.qtgui_time_sink_x_2.set_line_width(i, widths[i])
+ self.qtgui_time_sink_x_2.set_line_color(i, colors[i])
+ self.qtgui_time_sink_x_2.set_line_style(i, styles[i])
+ self.qtgui_time_sink_x_2.set_line_marker(i, markers[i])
+ self.qtgui_time_sink_x_2.set_line_alpha(i, alphas[i])
+
+ self._qtgui_time_sink_x_2_win = sip.wrapinstance(self.qtgui_time_sink_x_2.pyqwidget(), Qt.QWidget)
+ self.top_grid_layout.addWidget(self._qtgui_time_sink_x_2_win, 3, 0, 1, 1)
+ for r in range(3, 4):
+ self.top_grid_layout.setRowStretch(r, 1)
+ for c in range(0, 1):
+ self.top_grid_layout.setColumnStretch(c, 1)
+ self.qtgui_time_sink_x_1_1 = qtgui.time_sink_c(
+ 1024, #size
+ samp_rate, #samp_rate
+ "", #name
+ 1, #number of inputs
+ None # parent
+ )
+ self.qtgui_time_sink_x_1_1.set_update_time(0.10)
+ self.qtgui_time_sink_x_1_1.set_y_axis(-2, 2)
+
+ self.qtgui_time_sink_x_1_1.set_y_label('Equalized', "")
+
+ self.qtgui_time_sink_x_1_1.enable_tags(True)
+ self.qtgui_time_sink_x_1_1.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
+ self.qtgui_time_sink_x_1_1.enable_autoscale(True)
+ self.qtgui_time_sink_x_1_1.enable_grid(True)
+ self.qtgui_time_sink_x_1_1.enable_axis_labels(True)
+ self.qtgui_time_sink_x_1_1.enable_control_panel(False)
+ self.qtgui_time_sink_x_1_1.enable_stem_plot(False)
+
+
+ labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5',
+ 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10']
+ widths = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ colors = ['blue', 'red', 'green', 'black', 'cyan',
+ 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue']
+ alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0]
+ styles = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ markers = [-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1]
+
+
+ for i in range(2):
+ if len(labels[i]) == 0:
+ if (i % 2 == 0):
+ self.qtgui_time_sink_x_1_1.set_line_label(i, "Re{{Data {0}}}".format(i/2))
+ else:
+ self.qtgui_time_sink_x_1_1.set_line_label(i, "Im{{Data {0}}}".format(i/2))
+ else:
+ self.qtgui_time_sink_x_1_1.set_line_label(i, labels[i])
+ self.qtgui_time_sink_x_1_1.set_line_width(i, widths[i])
+ self.qtgui_time_sink_x_1_1.set_line_color(i, colors[i])
+ self.qtgui_time_sink_x_1_1.set_line_style(i, styles[i])
+ self.qtgui_time_sink_x_1_1.set_line_marker(i, markers[i])
+ self.qtgui_time_sink_x_1_1.set_line_alpha(i, alphas[i])
+
+ self._qtgui_time_sink_x_1_1_win = sip.wrapinstance(self.qtgui_time_sink_x_1_1.pyqwidget(), Qt.QWidget)
+ self.top_grid_layout.addWidget(self._qtgui_time_sink_x_1_1_win, 1, 0, 1, 1)
+ for r in range(1, 2):
+ self.top_grid_layout.setRowStretch(r, 1)
+ for c in range(0, 1):
+ self.top_grid_layout.setColumnStretch(c, 1)
+ self.qtgui_time_sink_x_1_0 = qtgui.time_sink_c(
+ 1024, #size
+ samp_rate, #samp_rate
+ "", #name
+ 1, #number of inputs
+ None # parent
+ )
+ self.qtgui_time_sink_x_1_0.set_update_time(0.10)
+ self.qtgui_time_sink_x_1_0.set_y_axis(-2, 2)
+
+ self.qtgui_time_sink_x_1_0.set_y_label('Modulated', "")
+
+ self.qtgui_time_sink_x_1_0.enable_tags(True)
+ self.qtgui_time_sink_x_1_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
+ self.qtgui_time_sink_x_1_0.enable_autoscale(True)
+ self.qtgui_time_sink_x_1_0.enable_grid(False)
+ self.qtgui_time_sink_x_1_0.enable_axis_labels(True)
+ self.qtgui_time_sink_x_1_0.enable_control_panel(False)
+ self.qtgui_time_sink_x_1_0.enable_stem_plot(False)
labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5',
@@ -125,19 +237,122 @@ class correlator(gr.top_block, Qt.QWidget):
for i in range(2):
if len(labels[i]) == 0:
if (i % 2 == 0):
- self.qtgui_time_sink_x_1.set_line_label(i, "Re{{Data {0}}}".format(i/2))
+ self.qtgui_time_sink_x_1_0.set_line_label(i, "Re{{Data {0}}}".format(i/2))
else:
- self.qtgui_time_sink_x_1.set_line_label(i, "Im{{Data {0}}}".format(i/2))
+ self.qtgui_time_sink_x_1_0.set_line_label(i, "Im{{Data {0}}}".format(i/2))
else:
- self.qtgui_time_sink_x_1.set_line_label(i, labels[i])
- self.qtgui_time_sink_x_1.set_line_width(i, widths[i])
- self.qtgui_time_sink_x_1.set_line_color(i, colors[i])
- self.qtgui_time_sink_x_1.set_line_style(i, styles[i])
- self.qtgui_time_sink_x_1.set_line_marker(i, markers[i])
- self.qtgui_time_sink_x_1.set_line_alpha(i, alphas[i])
-
- self._qtgui_time_sink_x_1_win = sip.wrapinstance(self.qtgui_time_sink_x_1.pyqwidget(), Qt.QWidget)
- self.top_layout.addWidget(self._qtgui_time_sink_x_1_win)
+ self.qtgui_time_sink_x_1_0.set_line_label(i, labels[i])
+ self.qtgui_time_sink_x_1_0.set_line_width(i, widths[i])
+ self.qtgui_time_sink_x_1_0.set_line_color(i, colors[i])
+ self.qtgui_time_sink_x_1_0.set_line_style(i, styles[i])
+ self.qtgui_time_sink_x_1_0.set_line_marker(i, markers[i])
+ self.qtgui_time_sink_x_1_0.set_line_alpha(i, alphas[i])
+
+ self._qtgui_time_sink_x_1_0_win = sip.wrapinstance(self.qtgui_time_sink_x_1_0.pyqwidget(), Qt.QWidget)
+ self.top_grid_layout.addWidget(self._qtgui_time_sink_x_1_0_win, 0, 0, 1, 1)
+ for r in range(0, 1):
+ self.top_grid_layout.setRowStretch(r, 1)
+ for c in range(0, 1):
+ self.top_grid_layout.setColumnStretch(c, 1)
+ self.qtgui_time_sink_x_0_0_0 = qtgui.time_sink_c(
+ 1024, #size
+ samp_rate, #samp_rate
+ "", #name
+ 1, #number of inputs
+ None # parent
+ )
+ self.qtgui_time_sink_x_0_0_0.set_update_time(0.10)
+ self.qtgui_time_sink_x_0_0_0.set_y_axis(-2, 2)
+
+ self.qtgui_time_sink_x_0_0_0.set_y_label('XC Magnitude', "")
+
+ self.qtgui_time_sink_x_0_0_0.enable_tags(True)
+ self.qtgui_time_sink_x_0_0_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
+ self.qtgui_time_sink_x_0_0_0.enable_autoscale(True)
+ self.qtgui_time_sink_x_0_0_0.enable_grid(False)
+ self.qtgui_time_sink_x_0_0_0.enable_axis_labels(True)
+ self.qtgui_time_sink_x_0_0_0.enable_control_panel(False)
+ self.qtgui_time_sink_x_0_0_0.enable_stem_plot(False)
+
+
+ labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5',
+ 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10']
+ widths = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ colors = ['blue', 'red', 'green', 'black', 'cyan',
+ 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue']
+ alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0]
+ styles = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ markers = [-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1]
+
+
+ for i in range(2):
+ if len(labels[i]) == 0:
+ if (i % 2 == 0):
+ self.qtgui_time_sink_x_0_0_0.set_line_label(i, "Re{{Data {0}}}".format(i/2))
+ else:
+ self.qtgui_time_sink_x_0_0_0.set_line_label(i, "Im{{Data {0}}}".format(i/2))
+ else:
+ self.qtgui_time_sink_x_0_0_0.set_line_label(i, labels[i])
+ self.qtgui_time_sink_x_0_0_0.set_line_width(i, widths[i])
+ self.qtgui_time_sink_x_0_0_0.set_line_color(i, colors[i])
+ self.qtgui_time_sink_x_0_0_0.set_line_style(i, styles[i])
+ self.qtgui_time_sink_x_0_0_0.set_line_marker(i, markers[i])
+ self.qtgui_time_sink_x_0_0_0.set_line_alpha(i, alphas[i])
+
+ self._qtgui_time_sink_x_0_0_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0_0_0.pyqwidget(), Qt.QWidget)
+ self.top_layout.addWidget(self._qtgui_time_sink_x_0_0_0_win)
+ self.qtgui_time_sink_x_0_0 = qtgui.time_sink_f(
+ 1024, #size
+ samp_rate, #samp_rate
+ "", #name
+ 1, #number of inputs
+ None # parent
+ )
+ self.qtgui_time_sink_x_0_0.set_update_time(0.10)
+ self.qtgui_time_sink_x_0_0.set_y_axis(0, 20)
+
+ self.qtgui_time_sink_x_0_0.set_y_label('XC Magnitude', "")
+
+ self.qtgui_time_sink_x_0_0.enable_tags(True)
+ self.qtgui_time_sink_x_0_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
+ self.qtgui_time_sink_x_0_0.enable_autoscale(True)
+ self.qtgui_time_sink_x_0_0.enable_grid(False)
+ self.qtgui_time_sink_x_0_0.enable_axis_labels(True)
+ self.qtgui_time_sink_x_0_0.enable_control_panel(False)
+ self.qtgui_time_sink_x_0_0.enable_stem_plot(False)
+
+
+ labels = ['Signal 1', 'Signal 2', 'Signal 3', 'Signal 4', 'Signal 5',
+ 'Signal 6', 'Signal 7', 'Signal 8', 'Signal 9', 'Signal 10']
+ widths = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ colors = ['blue', 'red', 'green', 'black', 'cyan',
+ 'magenta', 'yellow', 'dark red', 'dark green', 'dark blue']
+ alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0]
+ styles = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ markers = [-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1]
+
+
+ for i in range(1):
+ if len(labels[i]) == 0:
+ self.qtgui_time_sink_x_0_0.set_line_label(i, "Data {0}".format(i))
+ else:
+ self.qtgui_time_sink_x_0_0.set_line_label(i, labels[i])
+ self.qtgui_time_sink_x_0_0.set_line_width(i, widths[i])
+ self.qtgui_time_sink_x_0_0.set_line_color(i, colors[i])
+ self.qtgui_time_sink_x_0_0.set_line_style(i, styles[i])
+ self.qtgui_time_sink_x_0_0.set_line_marker(i, markers[i])
+ self.qtgui_time_sink_x_0_0.set_line_alpha(i, alphas[i])
+
+ self._qtgui_time_sink_x_0_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0_0.pyqwidget(), Qt.QWidget)
+ self.top_layout.addWidget(self._qtgui_time_sink_x_0_0_win)
self.qtgui_time_sink_x_0 = qtgui.time_sink_f(
1024, #size
samp_rate, #samp_rate
@@ -146,16 +361,16 @@ class correlator(gr.top_block, Qt.QWidget):
None # parent
)
self.qtgui_time_sink_x_0.set_update_time(0.10)
- self.qtgui_time_sink_x_0.set_y_axis(0, 50)
+ self.qtgui_time_sink_x_0.set_y_axis(0, 20)
- self.qtgui_time_sink_x_0.set_y_label('Amplitude', "")
+ self.qtgui_time_sink_x_0.set_y_label('XC Magnitude', "")
self.qtgui_time_sink_x_0.enable_tags(True)
self.qtgui_time_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, 0, "")
- self.qtgui_time_sink_x_0.enable_autoscale(False)
+ self.qtgui_time_sink_x_0.enable_autoscale(True)
self.qtgui_time_sink_x_0.enable_grid(False)
self.qtgui_time_sink_x_0.enable_axis_labels(True)
- self.qtgui_time_sink_x_0.enable_control_panel(True)
+ self.qtgui_time_sink_x_0.enable_control_panel(False)
self.qtgui_time_sink_x_0.enable_stem_plot(False)
@@ -185,10 +400,105 @@ class correlator(gr.top_block, Qt.QWidget):
self.qtgui_time_sink_x_0.set_line_alpha(i, alphas[i])
self._qtgui_time_sink_x_0_win = sip.wrapinstance(self.qtgui_time_sink_x_0.pyqwidget(), Qt.QWidget)
- self.top_layout.addWidget(self._qtgui_time_sink_x_0_win)
- self.fir_filter_xxx_1 = filter.fir_filter_ccc(1, [(-1.4142197+1.4142197j), (-1.4142197+1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197-1.4142197j), (-1.4142197+1.4142197j), (-1.4142197+1.4142197j), (1.4142197-1.4142197j), (1.4142197-1.4142197j)])
+ self.top_grid_layout.addWidget(self._qtgui_time_sink_x_0_win, 2, 0, 1, 1)
+ for r in range(2, 3):
+ self.top_grid_layout.setRowStretch(r, 1)
+ for c in range(0, 1):
+ self.top_grid_layout.setColumnStretch(c, 1)
+ self.qtgui_const_sink_x_1 = qtgui.const_sink_c(
+ 1024, #size
+ "Cross Correlation", #name
+ 1, #number of inputs
+ None # parent
+ )
+ self.qtgui_const_sink_x_1.set_update_time(0.10)
+ self.qtgui_const_sink_x_1.set_y_axis(-2, 2)
+ self.qtgui_const_sink_x_1.set_x_axis(-2, 2)
+ self.qtgui_const_sink_x_1.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, "")
+ self.qtgui_const_sink_x_1.enable_autoscale(True)
+ self.qtgui_const_sink_x_1.enable_grid(True)
+ self.qtgui_const_sink_x_1.enable_axis_labels(True)
+
+
+ labels = ['', '', '', '', '',
+ '', '', '', '', '']
+ widths = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ colors = ["blue", "red", "red", "red", "red",
+ "red", "red", "red", "red", "red"]
+ styles = [2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0]
+ markers = [9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0]
+ alphas = [.5, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0]
+
+ for i in range(1):
+ if len(labels[i]) == 0:
+ self.qtgui_const_sink_x_1.set_line_label(i, "Data {0}".format(i))
+ else:
+ self.qtgui_const_sink_x_1.set_line_label(i, labels[i])
+ self.qtgui_const_sink_x_1.set_line_width(i, widths[i])
+ self.qtgui_const_sink_x_1.set_line_color(i, colors[i])
+ self.qtgui_const_sink_x_1.set_line_style(i, styles[i])
+ self.qtgui_const_sink_x_1.set_line_marker(i, markers[i])
+ self.qtgui_const_sink_x_1.set_line_alpha(i, alphas[i])
+
+ self._qtgui_const_sink_x_1_win = sip.wrapinstance(self.qtgui_const_sink_x_1.pyqwidget(), Qt.QWidget)
+ self.top_grid_layout.addWidget(self._qtgui_const_sink_x_1_win, 2, 1, 2, 1)
+ for r in range(2, 4):
+ self.top_grid_layout.setRowStretch(r, 1)
+ for c in range(1, 2):
+ self.top_grid_layout.setColumnStretch(c, 1)
+ self.qtgui_const_sink_x_0 = qtgui.const_sink_c(
+ 1024, #size
+ "Equalized Signal", #name
+ 1, #number of inputs
+ None # parent
+ )
+ self.qtgui_const_sink_x_0.set_update_time(0.10)
+ self.qtgui_const_sink_x_0.set_y_axis(-2, 2)
+ self.qtgui_const_sink_x_0.set_x_axis(-2, 2)
+ self.qtgui_const_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, qtgui.TRIG_SLOPE_POS, 0.0, 0, "")
+ self.qtgui_const_sink_x_0.enable_autoscale(False)
+ self.qtgui_const_sink_x_0.enable_grid(False)
+ self.qtgui_const_sink_x_0.enable_axis_labels(True)
+
+
+ labels = ['', '', '', '', '',
+ '', '', '', '', '']
+ widths = [1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1]
+ colors = ["blue", "red", "red", "red", "red",
+ "red", "red", "red", "red", "red"]
+ styles = [0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0]
+ markers = [0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0]
+ alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0]
+
+ for i in range(1):
+ if len(labels[i]) == 0:
+ self.qtgui_const_sink_x_0.set_line_label(i, "Data {0}".format(i))
+ else:
+ self.qtgui_const_sink_x_0.set_line_label(i, labels[i])
+ self.qtgui_const_sink_x_0.set_line_width(i, widths[i])
+ self.qtgui_const_sink_x_0.set_line_color(i, colors[i])
+ self.qtgui_const_sink_x_0.set_line_style(i, styles[i])
+ self.qtgui_const_sink_x_0.set_line_marker(i, markers[i])
+ self.qtgui_const_sink_x_0.set_line_alpha(i, alphas[i])
+
+ self._qtgui_const_sink_x_0_win = sip.wrapinstance(self.qtgui_const_sink_x_0.pyqwidget(), Qt.QWidget)
+ self.top_grid_layout.addWidget(self._qtgui_const_sink_x_0_win, 0, 1, 2, 1)
+ for r in range(0, 2):
+ self.top_grid_layout.setRowStretch(r, 1)
+ for c in range(1, 2):
+ self.top_grid_layout.setColumnStretch(c, 1)
+ self.fir_filter_xxx_1 = filter.fir_filter_ccc(1, revconj_access_code_symbols)
self.fir_filter_xxx_1.declare_sample_delay(0)
self.digital_pfb_clock_sync_xxx_0 = digital.pfb_clock_sync_ccf(sps, timing_loop_bw, rrc_taps, nfilts, 16, 1.5, 1)
+ self.digital_corr_est_cc_0 = digital.corr_est_cc(access_code_symbols, 1, 0, .8, digital.THRESHOLD_DYNAMIC)
self.digital_constellation_modulator_0 = digital.generic_mod(
constellation=const,
differential=False,
@@ -198,28 +508,49 @@ class correlator(gr.top_block, Qt.QWidget):
verbose=False,
log=False,
truncate=False)
- self.digital_constellation_decoder_cb_0 = digital.constellation_decoder_cb(const)
self.digital_cma_equalizer_cc_0 = digital.cma_equalizer_cc(15, 1, .002, 1)
- self.blocks_vector_source_x_0 = blocks.vector_source_b(([0x00] * 10 + [0xaa, 0xff, 0x0a] + [0x00] * 10) * 20, False, 1, [])
- self.blocks_throttle_0 = blocks.throttle(gr.sizeof_char*1, samp_rate,True)
- self.blocks_null_sink_0 = blocks.null_sink(gr.sizeof_char*1)
- self.blocks_complex_to_mag_0 = blocks.complex_to_mag(1)
+ self.channels_channel_model_0 = channels.channel_model(
+ noise_voltage=0.2,
+ frequency_offset=0.000001,
+ epsilon=1.0,
+ taps=[-1.4 + .4j],
+ noise_seed=243,
+ block_tags=False)
+ self.blocks_vector_source_x_0 = blocks.vector_source_b(testvec * 1600, False, 1, [])
+ self.blocks_throttle_0 = blocks.throttle(gr.sizeof_gr_complex*1, samp_rate,True)
+ self.blocks_stream_mux_0 = blocks.stream_mux(gr.sizeof_char*1, [10, len(testvec)])
+ self.blocks_null_source_0 = blocks.null_source(gr.sizeof_char*1)
+ self.blocks_null_sink_3 = blocks.null_sink(gr.sizeof_float*1)
+ self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(180 / 3.141592653589793)
+ self.blocks_complex_to_magphase_0_0 = blocks.complex_to_magphase(1)
+ self.blocks_complex_to_magphase_0 = blocks.complex_to_magphase(1)
##################################################
# Connections
##################################################
- self.connect((self.blocks_complex_to_mag_0, 0), (self.qtgui_time_sink_x_0, 0))
- self.connect((self.blocks_throttle_0, 0), (self.digital_constellation_modulator_0, 0))
- self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_throttle_0, 0))
- self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_constellation_decoder_cb_0, 0))
+ self.connect((self.blocks_complex_to_magphase_0, 1), (self.blocks_multiply_const_vxx_0, 0))
+ self.connect((self.blocks_complex_to_magphase_0, 0), (self.qtgui_time_sink_x_0, 0))
+ self.connect((self.blocks_complex_to_magphase_0_0, 1), (self.blocks_null_sink_3, 0))
+ self.connect((self.blocks_complex_to_magphase_0_0, 0), (self.qtgui_time_sink_x_0_0, 0))
+ self.connect((self.blocks_multiply_const_vxx_0, 0), (self.qtgui_time_sink_x_2, 0))
+ self.connect((self.blocks_null_source_0, 0), (self.blocks_stream_mux_0, 0))
+ self.connect((self.blocks_stream_mux_0, 0), (self.digital_constellation_modulator_0, 0))
+ self.connect((self.blocks_throttle_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0))
+ self.connect((self.blocks_vector_source_x_0, 0), (self.blocks_stream_mux_0, 1))
+ self.connect((self.channels_channel_model_0, 0), (self.blocks_throttle_0, 0))
+ self.connect((self.digital_cma_equalizer_cc_0, 0), (self.digital_corr_est_cc_0, 0))
self.connect((self.digital_cma_equalizer_cc_0, 0), (self.fir_filter_xxx_1, 0))
- self.connect((self.digital_constellation_decoder_cb_0, 0), (self.blocks_null_sink_0, 0))
- self.connect((self.digital_constellation_modulator_0, 0), (self.digital_pfb_clock_sync_xxx_0, 0))
- self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1, 0))
+ self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_const_sink_x_0, 0))
+ self.connect((self.digital_cma_equalizer_cc_0, 0), (self.qtgui_time_sink_x_1_1, 0))
+ self.connect((self.digital_constellation_modulator_0, 0), (self.channels_channel_model_0, 0))
+ self.connect((self.digital_constellation_modulator_0, 0), (self.qtgui_time_sink_x_1_0, 0))
+ self.connect((self.digital_corr_est_cc_0, 1), (self.blocks_complex_to_magphase_0_0, 0))
+ self.connect((self.digital_corr_est_cc_0, 0), (self.qtgui_time_sink_x_0_0_0, 0))
self.connect((self.digital_pfb_clock_sync_xxx_0, 0), (self.digital_cma_equalizer_cc_0, 0))
- self.connect((self.fir_filter_xxx_1, 0), (self.blocks_complex_to_mag_0, 0))
+ self.connect((self.fir_filter_xxx_1, 0), (self.blocks_complex_to_magphase_0, 0))
+ self.connect((self.fir_filter_xxx_1, 0), (self.qtgui_const_sink_x_1, 0))
def closeEvent(self, event):
@@ -258,6 +589,13 @@ class correlator(gr.top_block, Qt.QWidget):
self.timing_loop_bw = timing_loop_bw
self.digital_pfb_clock_sync_xxx_0.set_loop_bandwidth(self.timing_loop_bw)
+ def get_testvec(self):
+ return self.testvec
+
+ def set_testvec(self, testvec):
+ self.testvec = testvec
+ self.blocks_vector_source_x_0.set_data(self.testvec * 1600, [])
+
def get_samp_rate(self):
return self.samp_rate
@@ -265,7 +603,11 @@ class correlator(gr.top_block, Qt.QWidget):
self.samp_rate = samp_rate
self.blocks_throttle_0.set_sample_rate(self.samp_rate)
self.qtgui_time_sink_x_0.set_samp_rate(self.samp_rate)
- self.qtgui_time_sink_x_1.set_samp_rate(self.samp_rate)
+ self.qtgui_time_sink_x_0_0.set_samp_rate(self.samp_rate)
+ self.qtgui_time_sink_x_0_0_0.set_samp_rate(self.samp_rate)
+ self.qtgui_time_sink_x_1_0.set_samp_rate(self.samp_rate)
+ self.qtgui_time_sink_x_1_1.set_samp_rate(self.samp_rate)
+ self.qtgui_time_sink_x_2.set_samp_rate(self.samp_rate)
def get_rrc_taps(self):
return self.rrc_taps
@@ -274,12 +616,31 @@ class correlator(gr.top_block, Qt.QWidget):
self.rrc_taps = rrc_taps
self.digital_pfb_clock_sync_xxx_0.update_taps(self.rrc_taps)
+ def get_revconj_access_code_symbols(self):
+ return self.revconj_access_code_symbols
+
+ def set_revconj_access_code_symbols(self, revconj_access_code_symbols):
+ self.revconj_access_code_symbols = revconj_access_code_symbols
+ self.fir_filter_xxx_1.set_taps(self.revconj_access_code_symbols)
+
def get_const(self):
return self.const
def set_const(self, const):
self.const = const
+ def get_access_code_symbols_sps(self):
+ return self.access_code_symbols_sps
+
+ def set_access_code_symbols_sps(self, access_code_symbols_sps):
+ self.access_code_symbols_sps = access_code_symbols_sps
+
+ def get_access_code_symbols(self):
+ return self.access_code_symbols
+
+ def set_access_code_symbols(self, access_code_symbols):
+ self.access_code_symbols = access_code_symbols
+