Let's consider the following class Signal which defines a multiphasic signal:
class Signal:
def __init__(self, fq, phases):
self.fq = fq
self.phases = phases
I created a function that generates Signal to test in another function.
# -*- coding: utf-8 -*-
import itertools
def duo_SBs_to_test(SB1, SB2, frequency_step = 1, shift_step = 50, max_shift = 20000, permutations = True):
upper_frequency = frequency_step + 1/(2*max(sum(SB1.phases), sum(SB2.phases)))*1000000
if SB1.fq <= 100 and SB2.fq <= 100:
r1 = 0.1
r2 = 0.1
upper1 = SB1.fq + r1*SB1.fq + frequency_step
upper2 = SB2.fq + r2*SB2.fq + frequency_step
elif SB1.fq <= 100 and SB2.fq > 100:
r1 = 0.1
r2 = 0.2
upper1 = SB1.fq + r1*SB1.fq + frequency_step
upper2 = SB2.fq + r2*SB2.fq + frequency_step
if upper2 > upper_frequency:
upper2 = upper_frequency
elif SB1.fq > 100 and SB2.fq <= 100:
r1 = 0.2
r2 = 0.1
upper1 = SB1.fq + r1*SB1.fq + frequency_step
upper2 = SB2.fq + r2*SB2.fq + frequency_step
if upper1 > upper_frequency:
upper1 = upper_frequency
else:
r1 = 0.2
r2 = 0.2
upper1 = SB1.fq + r1*SB1.fq + frequency_step
upper2 = SB2.fq + r2*SB2.fq + frequency_step
if upper1 > upper_frequency:
upper1 = upper_frequency
if upper2 > upper_frequency:
upper2 = upper_frequency
for s, f1, f2 in itertools.product(range(0, max_shift+shift_step, shift_step),
range(int(SB1.fq - r1*SB1.fq), int(upper1), frequency_step),
range(int(SB2.fq - r2*SB2.fq), int(upper2), frequency_step)):
yield (Signal(f1, SB1.phases), Signal(f2, SB2.phases), s)
if permutations:
yield (Signal(f2, SB2.phases), Signal(f1, SB1.phases), s)
Surprisingly, the performance isn't great. It's my first time creating a generator, and I guess I missed something.
%timeit res = [elt for elt in duo_SBs_to_test(SB1, SB3, frequency_step = 1,
shift_step = 50, max_shift = 20000, permutations = True)]
829 ms ± 11.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res = [elt for elt in duo_SBs_to_test(SB1, SB3, frequency_step = 1,
shift_step = 50, max_shift = 20000, permutations = True)]
842 ms ± 13.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit for elt in duo_SBs_to_test(SB1, SB3, frequency_step = 1,
shift_step = 50, max_shift = 20000, permutations = True): continue
765 ms ± 5.81 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit for elt in duo_SBs_to_test(SB1, SB3, frequency_step = 1,
shift_step = 50, max_shift = 20000, permutations = True): continue
768 ms ± 5.66 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
The former function I was using was storing frequency_to_test in a list, shifts in a numpy array before running the itertools.product() and storing in a list the Signals_to_test. Yet, it was just as fast...
EDIT:
SB1 = Signal(50, [300, 50, 900])
SB3 = Signal(80, [300, 50, 900])
Thanks for the tips :)
EDIT2: Next step:
def compute(SB1, SB2, frequency_step = 1, shift_step = 50, max_shift = 20000, permutations = True):
result = list()
for duo_generated in duo_SBs_to_test(SB1, SB2, frequency_step, shift_step, max_shift, permutations):
if not condition(duo_generated):
continue
else:
result.append(duo_generated)
return result
condition() is a function returning a boolean.
yield (SB(…), SB(…))do you meanSignal? Otherwise, please give the definition ofSB. Also, could you share the definition ofSB1andSB3so we can recreate your timings. \$\endgroup\$Signalis a bit different \$\endgroup\$Signalobjects why do you yield these crypticSBobjects. Besides, the signature of the constructor does not match (SBtake 3 parameters, butSignalonly 2). \$\endgroup\$Signal. \$\endgroup\$sparameter from the constructor means you could as well remove it from theproductand get way better performances… Can't you paste your real code instead? \$\endgroup\$