From aeea54c9acbc8945d0488526275d2f6692e20190 Mon Sep 17 00:00:00 2001 From: Sepehr Madani <ssepehrmadani@gmail.com> Date: Tue, 1 Sep 2020 00:21:44 -0400 Subject: [PATCH] Implement Butterfly Algorithm --- algorithms/butterfly_algorithm.py | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 algorithms/butterfly_algorithm.py diff --git a/algorithms/butterfly_algorithm.py b/algorithms/butterfly_algorithm.py new file mode 100644 index 0000000..9a85a37 --- /dev/null +++ b/algorithms/butterfly_algorithm.py @@ -0,0 +1,75 @@ +from math import pi, cos, sin, radians +from cmath import exp, phase +from .base_algorithm import BaseAlgorithm + +from utils.pattern import compute_pattern, compute_single_pattern +from utils.converter import vectorWrapToPi, wrapToPi + +class ButterflyAlgorithm(BaseAlgorithm): + """ Finds nulls by gradually widening the vectors + symmetrically (like a butterfly)to reduce the absolute + value of the pattern. + """ + + def __init__(self, options): + super().__init__(options) + self.main_ang = options.main_ang + self.null_degrees = options.null_degrees + self.bit_count = options.bit_count + self.bit_resolution = options.bit_resolution + self.pattern = 0 + + self.check_parameters() + + def check_parameters(self): + super().check_parameters() + assert len(self.null_degrees) == 1 + + def get_pattern(self): + pattern_values = compute_pattern( + N=self.N, + k=self.k, + weights=[exp(1j * x) for x in self.vector_changes], + degrees=self.null_degrees, + use_absolute_value=False + ) + self.pattern = pattern_values[0].conjugate() + print(f'{abs(self.pattern) = }') + + def solve(self): + alpha = (2*pi) / (2**self.bit_resolution) + + self.null_deg = self.null_degrees[0] + self.theta = pi * cos(radians(self.null_deg)) + self.sum_dir = self.theta * (self.N - 1) / 2 + self.vector_dirs = [k * self.theta for k in range(self.N)] + self.vector_diffs = vectorWrapToPi([x - self.sum_dir for x in self.vector_dirs]) + self.vector_changes = [0 for _ in range(self.N)] + + self.get_pattern() + + hasTurned = False + while not hasTurned: + for idx in range(self.N // 2): + old_change = self.vector_changes[:] + other = self.N - 1 - idx + angle_with_sum = wrapToPi(self.vector_diffs[idx] + self.vector_changes[idx]) + + if 0 <= angle_with_sum < pi - alpha/2: + self.vector_changes[idx] += alpha + self.vector_changes[other] -= alpha + elif -pi + alpha/2 < angle_with_sum <= 0: + self.vector_changes[idx] -= alpha + self.vector_changes[other] += alpha + + self.vector_diffs = vectorWrapToPi(self.vector_diffs) + self.vector_changes = vectorWrapToPi(self.vector_changes) + + self.get_pattern() + + if (hasTurned := abs(cos(phase(self.pattern) - self.sum_dir) + 1) < 1e-9): + break + + self.vector_changes = old_change[:] + self.get_pattern() + -- GitLab