aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-08-21 08:24:44 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-08-21 08:24:44 +0200
commit4c3d8c6b3162ddaca3b57ecd8467d99e85eeaa1b (patch)
tree52b8be114cdf18037d27216c3e8c411b6d4909ee
parentf168dadf5e02a3c861455dbcd071d3354ebbf83e (diff)
downloadmmbtools-aux-4c3d8c6b3162ddaca3b57ecd8467d99e85eeaa1b.tar.gz
mmbtools-aux-4c3d8c6b3162ddaca3b57ecd8467d99e85eeaa1b.tar.bz2
mmbtools-aux-4c3d8c6b3162ddaca3b57ecd8467d99e85eeaa1b.zip
analyse_tii_from_file can read u8
-rwxr-xr-xtii/analyse_tii_from_file.py77
1 files changed, 56 insertions, 21 deletions
diff --git a/tii/analyse_tii_from_file.py b/tii/analyse_tii_from_file.py
index 9d834ea..32a5582 100755
--- a/tii/analyse_tii_from_file.py
+++ b/tii/analyse_tii_from_file.py
@@ -138,6 +138,18 @@ prs_phases = np.array([0, -1, 1, -1, -1, -1, -1, 0, 0, 1, -1, -1, -1, 1, 1, 0, 0
1, 0, 0, 1, 0, -1, 0, -1, 1, 0, 2, -1, 0, -1, 2, 1, 1, 0, 0, 1, 0, -1, 0, -1,
1, 0])
+def load_iq(filename, u8, count):
+ if u8:
+ u8_interleaved = np.fromfile(filename, np.uint8, count=count)
+ u8_iq = u8_interleaved.reshape(int(len(u8_interleaved)/2), 2)
+ # This directly converts to fc64
+ fc64_unscaled = u8_iq[...,0] + np.complex64(1j) * u8_iq[...,1]
+ fc64_scaled = (fc64_unscaled - 127.0) / 128.0
+ #fc64_dc_comp = fc64_scaled - np.average(fc64_scaled)
+ return fc64_scaled
+ else:
+ return np.fromfile(filename, np.complex64, count=count)
+
def main():
parser = argparse.ArgumentParser(description="Plot TII")
parser.add_argument('--frame', default='0', help='Which transmission frame to analyse',
@@ -146,10 +158,14 @@ def main():
required=False)
parser.add_argument('--iq-file', default='ofdm.iq', help='File to read',
required=False)
- parser.add_argument('--test-combs', action='store_const', const=True, help='Test all comb pattern values',
- required=False)
- parser.add_argument('--old-algo', action='store_const', const=True, help='Do an analysis with the old algorithm',
- required=False)
+ parser.add_argument('--test-combs', action='store_const', const=True,
+ help='Test all comb pattern values', required=False)
+ parser.add_argument('--old-algo', action='store_const', const=True,
+ help='Do an analysis with the old algorithm', required=False)
+ parser.add_argument('--u8', action='store_const', const=True,
+ help='File is in u8 and not cf32 format', required=False)
+ parser.add_argument('--align', action='store_const', const=True,
+ help='Find NULL and align to it', required=False)
cli_args = parser.parse_args()
@@ -164,9 +180,9 @@ def main():
prepare_tii_patterns()
algo1(cli_args)
-tii_ini_template = open("tii.ini.template", "r").read()
def prepare_comb_pattern_run(options, comb, pattern):
+ tii_ini_template = open("tii.ini.template", "r").read()
fd = open("tii.ini", "w")
fd.write(tii_ini_template.format(comb=comb, pattern=pattern, oldvariant=0))
fd.close()
@@ -183,6 +199,17 @@ def prepare_comb_pattern_run(options, comb, pattern):
else:
print("== FAIL {}".format(ret))
+def advance_to_null(frames):
+ for i in range(0, len(frames), NullSize//2):
+ if np.all(np.abs(frames[i:i+NullSize//2]) < 1e-2):
+ print("NULL at?", i)
+ # First non-zero sample is first PRS sample
+ for j in range(NullSize):
+ if np.abs(frames[i+j]) > 1e-2:
+ print("NULL at ", i+j - NullSize)
+ return frames[i+j - NullSize:]
+ print("NULL not found")
+ sys.exit(1)
def plot_tii_once(options):
oversample = int(int(options.samplerate) / 2048000)
@@ -192,7 +219,7 @@ def plot_tii_once(options):
N = 8
num_samples = num_samples_per_tf * (int(options.frame) + N)
- frames = np.fromfile(options.iq_file, np.complex64, count=num_samples)
+ frames = load_iq(options.iq_file, options.u8, count=num_samples)
#skip to frame
frames = frames[num_samples_per_tf * int(options.frame):]
@@ -306,7 +333,10 @@ def algo1(options):
N = 8
num_samples = num_samples_per_tf * (int(options.frame) + N)
- frames = np.fromfile(options.iq_file, np.complex64, count=num_samples)
+ frames = load_iq(options.iq_file, options.u8, count=num_samples)
+
+ if options.align:
+ frames = advance_to_null(frames)
#skip to frame
frames = frames[num_samples_per_tf * int(options.frame):]
@@ -334,17 +364,22 @@ def algo1(options):
# A consequence of the fact that the 0 bin is never used is that the
# first carrier of each pair is even for negative k, odd for positive k
- blocks = [null_fft[-769:-385], null_fft[-385:-1], null_fft[1:385], null_fft[385:769]]
+ blocks = [null_fft[-768:-384], null_fft[-384:], null_fft[1:385], null_fft[385:769]]
blocks_multiplied = np.zeros(384//2, dtype=np.complex128)
+ #print("blocks {}".format(i))
for block in blocks:
even_odd = block.reshape(-1, 2)
b = even_odd[...,0] * np.conj(even_odd[...,1])
+ #print("".join('#' if i else '.' for i in np.abs(b) > 1e-7))
blocks_multiplied += b
threshold = 0.01
indices_above_threshold = np.nonzero(np.abs(blocks_multiplied) > threshold)[0]
carrier_indices = indices_above_threshold * 2 + 1
+ if len(frame) < NullSize:
+ break
+
if np.max(np.abs(frame[:NullSize])) != 0:
print("Frame {} has nonzero power in null symbol and {} TII carriers".format(i, len(carrier_indices)))
@@ -361,6 +396,7 @@ def algo1(options):
cp_counts[cp] += 1
if len(cp_counts) > 0:
+ print(carriers)
for cp in cp_counts:
if cp_counts[cp] >= 4:
c, p = cp
@@ -376,11 +412,11 @@ def algo1(options):
print("Unrecognised TII comb and pattern")
def convert_angles(angle):
- """Convert 0 to 360 degree angles to 0 to 180, -179 to -1"""
- if angle > 180:
- return angle - 360
- elif angle < -180:
- return angle + 360
+ """Convert 0 to 2pi degree angles to -pi to pi"""
+ if angle * 2.0 > np.pi:
+ return angle - 2*np.pi
+ elif angle * 2.0 < -np.pi:
+ return angle + 2*np.pi
else:
return angle
phase_corrector = np.vectorize(convert_angles)
@@ -391,24 +427,23 @@ def analyse_phase(c, p, null_fft, prs_fft):
#print("k =" + " ".join("{:>4}".format(k) for k in carriers))
#print("phases =" + " ".join("{:>4}".format(int(round(p))) for p in np.angle(prs_fft[carriers], deg=True)))
- phases_tii = np.angle(null_fft[carriers], deg=True)
+ phases_tii = np.angle(null_fft[carriers])
pair_indices = carriers.reshape(-1,2)[...,0]
correct_phase_indices = np.stack([pair_indices, pair_indices]).T.flatten()
- phases_prs2 = np.angle(prs_fft[correct_phase_indices], deg=True)
+ phases_prs2 = np.angle(prs_fft[correct_phase_indices])
fig = pp.figure()
fig.suptitle("Phase error C {} P {}".format(c, p))
phase_errors = {}
- search_range = (-40, 40)
- for err4 in range(*search_range):
- err = err4 / 4
+ search_range = (-20, 500)
+ for err in range(*search_range):
rotate_vec = np.exp(2j * np.pi * err * carriers / 2048)
- rotated = np.angle(null_fft[carriers] * rotate_vec, deg=True)
- delta = np.mod(np.asarray(np.around(rotated - phases_prs2), dtype=np.int), 360)
+ rotated = null_fft[carriers] * rotate_vec
+ delta = np.asarray(np.around(np.angle(rotated) - phases_prs2), dtype=np.int)
delta = phase_corrector(delta)
- #print("phases {:>3} =".format(err) + " ".join("{:>4}".format(p) for p in delta))
+ #print("phases {:>3} =".format(err) + " ".join("{:>4}".format(int(180*p/np.pi)) for p in delta))
phase_errors[err] = delta
#ax1 = fig.add_subplot(7, 1, i+1)