aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdpd/apply_adapt_dumps.py132
-rw-r--r--dpd/dpd.ini2
-rwxr-xr-xdpd/main.py2
-rw-r--r--dpd/src/Adapt.py10
-rw-r--r--dpd/src/Const.py6
-rw-r--r--dpd/src/Dab_Util.py15
-rw-r--r--dpd/src/ExtractStatistic.py8
-rw-r--r--dpd/src/MER.py8
-rw-r--r--dpd/src/Measure.py2
-rw-r--r--dpd/src/Measure_Shoulders.py8
-rw-r--r--dpd/src/Model.py6
-rw-r--r--dpd/src/Model_AM.py8
-rw-r--r--dpd/src/Model_Lut.py6
-rw-r--r--dpd/src/Model_PM.py8
-rw-r--r--dpd/src/Model_Poly.py6
-rw-r--r--dpd/src/RX_Agc.py8
-rw-r--r--dpd/src/Symbol_align.py4
-rw-r--r--dpd/src/TX_Agc.py5
-rw-r--r--dpd/src/phase_align.py7
-rwxr-xr-xdpd/src/subsample_align.py8
20 files changed, 92 insertions, 167 deletions
diff --git a/dpd/apply_adapt_dumps.py b/dpd/apply_adapt_dumps.py
index 6b15aff..f1f3359 100755
--- a/dpd/apply_adapt_dumps.py
+++ b/dpd/apply_adapt_dumps.py
@@ -6,38 +6,16 @@
# http://www.opendigitalradio.org
# Licence: The MIT License, see notice at the end of this file
-"""This Python script is the main file for ODR-DabMod's DPD Computation Engine.
-This engine calculates and updates the parameter of the digital
-predistortion module of ODR-DabMod."""
-
import datetime
import os
-import matplotlib
import glob
-import natsort
-matplotlib.use('GTKAgg')
-
import logging
dt = datetime.datetime.now().isoformat()
-logging_path = "/tmp/dpd_{}".format(dt).replace(".", "_").replace(":", "-")
-os.makedirs(logging_path)
logging.basicConfig(format='%(asctime)s - %(module)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
- filename='{}/dpd.log'.format(logging_path),
- filemode='w',
level=logging.DEBUG)
-# also log up to INFO to console
-console = logging.StreamHandler()
-console.setLevel(logging.INFO)
-# set a format which is simpler for console use
-formatter = logging.Formatter('%(asctime)s - %(module)s - %(levelname)s - %(message)s')
-# tell the handler to use this format
-console.setFormatter(formatter)
-# add the handler to the root logger
-logging.getLogger('').addHandler(console)
-
import src.Measure as Measure
import src.Model as Model
import src.ExtractStatistic as ExtractStatistic
@@ -59,120 +37,22 @@ parser.add_argument('--port', default=50055, type=int,
parser.add_argument('--rc-port', default=9400, type=int,
help='port of ODR-DabMod ZMQ Remote Control to connect to (default: 9400)',
required=False)
-parser.add_argument('--samplerate', default=8192000, type=int,
- help='Sample rate',
- required=False)
-parser.add_argument('--coefs', default='/tmp/poly.coef',
+parser.add_argument('--coefs', default='poly.coef',
help='File with DPD coefficients, which will be read by ODR-DabMod',
required=False)
-parser.add_argument('--txgain', default=75,
- help='TX Gain',
- required=False,
- type=int)
-parser.add_argument('--rxgain', default=30,
- help='TX Gain',
- required=False,
- type=int)
-parser.add_argument('--digital_gain', default=1,
- help='Digital Gain',
- required=False,
- type=float)
-parser.add_argument('--samps', default='81920', type=int,
- help='Number of samples to request from ODR-DabMod',
- required=False)
-parser.add_argument('--target_median', default=0.1,
- help='target_median',
- required=False,
- type=float)
-parser.add_argument('--searchpath', default='./stored', type=str,
- help='Path to search .pkl files with stored configuration'
- 'for adapt',
- required=False)
-parser.add_argument('-L', '--lut',
- help='Use lookup table instead of polynomial predistorter',
- action="store_true")
+parser.add_argument('file', help='File to read the DPD settings from')
cli_args = parser.parse_args()
port = cli_args.port
port_rc = cli_args.rc_port
coef_path = cli_args.coefs
-digital_gain = cli_args.digital_gain
-txgain = cli_args.txgain
-rxgain = cli_args.rxgain
-num_req = cli_args.samps
-samplerate = cli_args.samplerate
-searchpath = cli_args.searchpath
-target_median = cli_args.target_median
-
-c = src.Const.Const(samplerate, target_median, False)
-SA = src.Symbol_align.Symbol_align(c)
-MER = src.MER.MER(c)
-MS = src.Measure_Shoulders.Measure_Shoulders(c)
-
-meas = Measure.Measure(samplerate, port, num_req)
-extStat = ExtractStatistic.ExtractStatistic(c)
-adapt = Adapt.Adapt(port_rc, coef_path)
-dpddata = adapt.get_predistorter
-
-if cli_args.lut:
- model = Model.Lut(c)
-else:
- model = Model.Poly(c)
-adapt.set_predistorter(model.get_dpd_data())
-adapt.set_digital_gain(digital_gain)
-adapt.set_txgain(txgain)
-adapt.set_rxgain(rxgain)
-
-tx_gain = adapt.get_txgain()
-rx_gain = adapt.get_rxgain()
-digital_gain = adapt.get_digital_gain()
-
-dpddata = adapt.get_predistorter()
-if dpddata[0] == "poly":
- coefs_am = dpddata[1]
- coefs_pm = dpddata[2]
- logging.info(
- "TX gain {}, RX gain {}, dpd_coefs_am {},"
- " dpd_coefs_pm {}, digital_gain {}".format(
- tx_gain, rx_gain, coefs_am, coefs_pm, digital_gain
- )
- )
-elif dpddata[0] == "lut":
- scalefactor = dpddata[1]
- lut = dpddata[2]
- logging.info(
- "TX gain {}, RX gain {}, LUT scalefactor {},"
- " LUT {}, digital_gain {}".format(
- tx_gain, rx_gain, scalefactor, lut, digital_gain
- )
- )
-else:
- logging.error("Unknown dpd data format {}".format(dpddata[0]))
-
-tx_agc = TX_Agc.TX_Agc(adapt, c)
-
-# Automatic Gain Control
-agc = Agc.Agc(meas, adapt, c)
-agc.run()
-
-paths = natsort.natsorted(glob.glob(searchpath + "/*.pkl"))
-print(paths)
-
-for i, path in enumerate(paths):
- print(i, path)
- adapt.load(path)
- dpddata_after = adapt.get_predistorter()
-
- coefs_am, coefs_pm = model.reset_coefs()
- adapt.set_predistorter(("poly", coefs_am, coefs_pm))
- print("Loaded configuration without pre-distortion")
+filename = cli_args.file
- raw_input("Key for pre-distortion ")
- adapt.set_predistorter(dpddata_after)
- print("Pre-distortion done")
+adapt = Adapt(port_rc, coef_path)
- raw_input("Key for next ")
+print("Loading and applying DPD settings from {}".format(filename))
+adapt.load(filename)
# The MIT License (MIT)
#
diff --git a/dpd/dpd.ini b/dpd/dpd.ini
index 7e4bd5f..af5c2fb 100644
--- a/dpd/dpd.ini
+++ b/dpd/dpd.ini
@@ -18,7 +18,7 @@ gainmode=var
rate=8192000
# keep in mind that the DPDCE will set the digital gain through the RC!
-digital_gain=0.6
+digital_gain=0.01
[firfilter]
enabled=1
diff --git a/dpd/main.py b/dpd/main.py
index 49c0d1d..e15c6b5 100755
--- a/dpd/main.py
+++ b/dpd/main.py
@@ -45,7 +45,7 @@ parser.add_argument('--digital_gain', default=0.6,
required=False,
type=float)
parser.add_argument('--target_median', default=0.05,
- help='target_median',
+ help='The target median for the RX and TX AGC',
required=False,
type=float)
parser.add_argument('--samps', default='81920', type=int,
diff --git a/dpd/src/Adapt.py b/dpd/src/Adapt.py
index 7e19a2c..c78c920 100644
--- a/dpd/src/Adapt.py
+++ b/dpd/src/Adapt.py
@@ -16,7 +16,10 @@ import os
import datetime
import pickle
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
LUT_LEN = 32
FORMAT_POLY = 1
@@ -226,7 +229,10 @@ class Adapt:
"""Backup current settings to a file"""
dt = datetime.datetime.now().isoformat()
if path is None:
- path = logging_path + "/" + dt + "_adapt.pkl"
+ if logging_path is not None:
+ path = logging_path + "/" + dt + "_adapt.pkl"
+ else:
+ raise Exception("Cannot dump Adapt without either logging_path or path set")
d = {
"txgain": self.get_txgain(),
"rxgain": self.get_rxgain(),
diff --git a/dpd/src/Const.py b/dpd/src/Const.py
index 6c9bafa..d80cfac 100644
--- a/dpd/src/Const.py
+++ b/dpd/src/Const.py
@@ -73,14 +73,14 @@ class Const:
self.MPM_tx_min = 0.1
# Constants for TX_Agc
- self.TAGC_max_txgain = 89 # USRP specific
+ self.TAGC_max_txgain = 89 # USRP B200 specific
self.TAGC_tx_median_target = target_median
self.TAGC_tx_median_max = self.TAGC_tx_median_target * 1.4
self.TAGC_tx_median_min = self.TAGC_tx_median_target / 1.4
# Constants for RX_AGC
- self.RAGC_min_rxgain = 25 # USRP specific
- self.RAGC_rx_median_target = self.TAGC_tx_median_target
+ self.RAGC_min_rxgain = 25 # USRP B200 specific
+ self.RAGC_rx_median_target = target_median
# The MIT License (MIT)
#
diff --git a/dpd/src/Dab_Util.py b/dpd/src/Dab_Util.py
index 2021f38..56c9503 100644
--- a/dpd/src/Dab_Util.py
+++ b/dpd/src/Dab_Util.py
@@ -9,7 +9,10 @@ import datetime
import os
import logging
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib
@@ -53,7 +56,7 @@ class Dab_Util:
off = sig_rec.shape[0]
c = np.abs(signal.correlate(sig_orig, sig_rec))
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
corr_path = (logging_path + "/" + dt + "_tx_rx_corr.svg")
plt.plot(c, label="corr")
@@ -107,7 +110,7 @@ class Dab_Util:
Returns an aligned version of sig_tx and sig_rx by cropping and subsample alignment
"""
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_sync_raw.svg"
@@ -151,7 +154,7 @@ class Dab_Util:
sig_tx = sig_tx[:-1]
sig_rx = sig_rx[:-1]
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_sync_sample_aligned.svg"
@@ -175,7 +178,7 @@ class Dab_Util:
sig_rx = sa.subsample_align(sig_rx, sig_tx)
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_sync_subsample_aligned.svg"
@@ -199,7 +202,7 @@ class Dab_Util:
sig_rx = pa.phase_align(sig_rx, sig_tx)
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_sync_phase_aligned.svg"
diff --git a/dpd/src/ExtractStatistic.py b/dpd/src/ExtractStatistic.py
index d27cd77..e917909 100644
--- a/dpd/src/ExtractStatistic.py
+++ b/dpd/src/ExtractStatistic.py
@@ -12,8 +12,10 @@ import matplotlib.pyplot as plt
import datetime
import os
import logging
-
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
def _check_input_extract(tx_dpd, rx_received):
@@ -64,7 +66,7 @@ class ExtractStatistic:
self.plot = c.ES_plot
def _plot_and_log(self, tx_values, rx_values, phase_diffs_values, phase_diffs_values_lists):
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_ExtractStatistic.png"
diff --git a/dpd/src/MER.py b/dpd/src/MER.py
index f186261..a4c3591 100644
--- a/dpd/src/MER.py
+++ b/dpd/src/MER.py
@@ -11,7 +11,7 @@ import logging
try:
logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
except:
- logging_path = "/tmp/"
+ logging_path = None
import numpy as np
import matplotlib
@@ -76,9 +76,11 @@ class MER:
spectrum = self._calc_spectrum(tx)
- if self.plot:
+ if self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_MER" + debug_name + ".svg"
+ else:
+ fig_path = None
MERs = []
for i, (x, y) in enumerate(self._split_in_carrier(
@@ -103,7 +105,7 @@ class MER:
ylim = ax.get_ylim()
ax.set_ylim(ylim[0] - (ylim[1] - ylim[0]) * 0.1, ylim[1])
- if self.plot:
+ if fig_path is not None:
plt.tight_layout()
plt.savefig(fig_path)
plt.show()
diff --git a/dpd/src/Measure.py b/dpd/src/Measure.py
index d4b1d9e..e4333d9 100644
--- a/dpd/src/Measure.py
+++ b/dpd/src/Measure.py
@@ -11,9 +11,7 @@ import struct
import numpy as np
import src.Dab_Util as DU
import os
-
import logging
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
class Measure:
"""Collect Measurement from DabMod"""
diff --git a/dpd/src/Measure_Shoulders.py b/dpd/src/Measure_Shoulders.py
index c733dfd..2249ac6 100644
--- a/dpd/src/Measure_Shoulders.py
+++ b/dpd/src/Measure_Shoulders.py
@@ -10,7 +10,10 @@ import os
import logging
import multiprocessing
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib.pyplot as plt
@@ -79,6 +82,9 @@ class Measure_Shoulders:
self.plot = c.MS_plot
def _plot(self, signal):
+ if logging_path is None:
+ return
+
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_sync_subsample_aligned.svg"
diff --git a/dpd/src/Model.py b/dpd/src/Model.py
index 67feeb6..b2c303f 100644
--- a/dpd/src/Model.py
+++ b/dpd/src/Model.py
@@ -2,6 +2,12 @@
from src.Model_Poly import Poly
from src.Model_Lut import Lut
+def select_model_from_dpddata(dpddata):
+ if dpddata[0] == 'lut':
+ return Lut
+ elif dpddata[0] == 'poly':
+ return Poly
+
# The MIT License (MIT)
#
# Copyright (c) 2017 Andreas Steger
diff --git a/dpd/src/Model_AM.py b/dpd/src/Model_AM.py
index d7e880c..596ca4a 100644
--- a/dpd/src/Model_AM.py
+++ b/dpd/src/Model_AM.py
@@ -8,8 +8,10 @@
import datetime
import os
import logging
-
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib.pyplot as plt
@@ -55,7 +57,7 @@ class Model_AM:
self.plot = plot
def _plot(self, tx_dpd, rx_received, coefs_am, coefs_am_new):
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
tx_range, rx_est = calc_line(coefs_am, 0, 0.6)
tx_range_new, rx_est_new = calc_line(coefs_am_new, 0, 0.6)
diff --git a/dpd/src/Model_Lut.py b/dpd/src/Model_Lut.py
index 6d4db52..b349433 100644
--- a/dpd/src/Model_Lut.py
+++ b/dpd/src/Model_Lut.py
@@ -7,8 +7,10 @@
import os
import logging
-
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
diff --git a/dpd/src/Model_PM.py b/dpd/src/Model_PM.py
index d4f8c00..e721d1a 100644
--- a/dpd/src/Model_PM.py
+++ b/dpd/src/Model_PM.py
@@ -8,8 +8,10 @@
import datetime
import os
import logging
-
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib.pyplot as plt
@@ -41,7 +43,7 @@ class Model_PM:
self.plot = plot
def _plot(self, tx_dpd, phase_diff, coefs_pm, coefs_pm_new):
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
tx_range, phase_diff_est = self.calc_line(coefs_pm, 0, 0.6)
tx_range_new, phase_diff_est_new = self.calc_line(coefs_pm_new, 0, 0.6)
diff --git a/dpd/src/Model_Poly.py b/dpd/src/Model_Poly.py
index ff15941..1cf8ecd 100644
--- a/dpd/src/Model_Poly.py
+++ b/dpd/src/Model_Poly.py
@@ -7,8 +7,10 @@
import os
import logging
-
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
diff --git a/dpd/src/RX_Agc.py b/dpd/src/RX_Agc.py
index 670fbbb..7b5e0b6 100644
--- a/dpd/src/RX_Agc.py
+++ b/dpd/src/RX_Agc.py
@@ -9,7 +9,10 @@ import datetime
import os
import logging
import time
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib
@@ -70,6 +73,9 @@ class Agc:
def plot_estimates(self):
"""Plots the estimate of for Max, Median, Mean for different
number of samples."""
+ if logging_path is None:
+ return
+
self.adapt.set_rxgain(self.min_rxgain)
time.sleep(1)
diff --git a/dpd/src/Symbol_align.py b/dpd/src/Symbol_align.py
index d921f25..f2802ee 100644
--- a/dpd/src/Symbol_align.py
+++ b/dpd/src/Symbol_align.py
@@ -12,7 +12,7 @@ import logging
try:
logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
except:
- logging_path = "/tmp/"
+ logging_path = None
import numpy as np
import scipy
@@ -75,7 +75,7 @@ class Symbol_align:
offset = peaks[np.argmin([tx_product_avg[peak] for peak in peaks])]
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and self.plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_Symbol_align.svg"
diff --git a/dpd/src/TX_Agc.py b/dpd/src/TX_Agc.py
index 3c804fa..7555450 100644
--- a/dpd/src/TX_Agc.py
+++ b/dpd/src/TX_Agc.py
@@ -10,7 +10,10 @@ import os
import logging
import time
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib
diff --git a/dpd/src/phase_align.py b/dpd/src/phase_align.py
index 68c216d..21a210c 100644
--- a/dpd/src/phase_align.py
+++ b/dpd/src/phase_align.py
@@ -7,7 +7,10 @@
import datetime
import os
import logging
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
import matplotlib.pyplot as plt
@@ -24,7 +27,7 @@ def phase_align(sig, ref_sig, plot=False):
real_diffs = np.cos(angle_diff)
imag_diffs = np.sin(angle_diff)
- if logging.getLogger().getEffectiveLevel() == logging.DEBUG and plot:
+ if logging.getLogger().getEffectiveLevel() == logging.DEBUG and plot and logging_path is not None:
dt = datetime.datetime.now().isoformat()
fig_path = logging_path + "/" + dt + "_phase_align.svg"
diff --git a/dpd/src/subsample_align.py b/dpd/src/subsample_align.py
index 68f3591..a5e9f8c 100755
--- a/dpd/src/subsample_align.py
+++ b/dpd/src/subsample_align.py
@@ -7,8 +7,10 @@
import datetime
import logging
import os
-
-logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+try:
+ logging_path = os.path.dirname(logging.getLoggerClass().root.handlers[0].baseFilename)
+except AttributeError:
+ logging_path = None
import numpy as np
from scipy import optimize
@@ -72,7 +74,7 @@ def subsample_align(sig, ref_sig, plot=False):
if optim_result.success:
best_tau = optim_result.x
- if plot:
+ if plot and logging_path is not None:
corr = np.vectorize(correlate_for_delay)
ixs = np.linspace(-1, 1, 100)
taus = corr(ixs)