Мне стало любопытно, можно ли реализовать такой треугольный осциллятор без условий и перечислений. Ну, один из вариантов следующий:
def oscillator(magnitude):
i = 0
x = y = -1
double_magnitude = magnitude + magnitude
while True:
yield i
x = (x + 1) * (1 - (x // (double_magnitude - 1))) # instead of (x + 1) % double_magnitude
y = (y + 1) * (1 - (y // (magnitude - 1))) # instead of (y + 1) % magnitude
difference = x - y # difference ∈ {0, magnitude}
derivative = (-1 * (difference > 0) + 1 * (difference == 0))
i += derivative
Идея заключается в том, чтобы взять 2 пилообразные волны с разными периодами и вычесть одну из другой. Результатом будет прямоугольная волна со значениями в {0, величина}. Затем мы просто заменим {0, величина} на {-1, +1} соответственно, чтобы получить производные значения для нашего целевого сигнала.
Давайте рассмотрим пример с magnitude = 5
:
o = oscillator(5)
[next(o) for _ in range(21)]
Это выводит [0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0]
.
Если разрешено abs()
, его можно использовать для простоты. Например, следующий код выдает тот же вывод, что и выше:
[abs(5 - ((x + 5) % 10)) for x in range(21)]