Сообщество Engee

Быстрое прототипирование алгоритма управления гирляндой

Автор
avatar-ilyaberdyshevilyaberdyshev
Соавторы
avatar-daniil_timofeevdaniil_timofeev
Notebook

Быстрое прототипирование алгоритма управления гирляндой

В преддверии Нового года всегда хочется создать особую атмосферу. В этом примере показано, как с помощью КПМ РИТМ можно разработать алгоритм управления светодиодной гирляндой, которая будет менять свою яркость в зависимости от громкости музыки, создавая эффект "танцующих огоньков".

В данном примере показано, как использовать машину реального времени — КПМ РИТМ для быстрого прототипирования алгоритмов управления. Объектом управления является светодиодная гирлянда. Алгоритм управления регулирует яркость гирлянды пропорционально громкости музыки. Сначала аудиофайл обрабатывается с помощью скрипта, и затем полученный сигнал загружается в модель на КПМ РИТМ.

Модель, запускаемая на КПМ РИТМ, содержит подсистему Звуковой сигнал, в которой загружается вектор обработанных значений амплитуд аудиофайла из рабочей области. В первые 2 секунды подсистема выдает значение 1 для синхронизации звука. Воспроизведение сигнала происходит циклически — после достижения конца аудиофайла он воспроизводится с начала.

Амплитуда сигнала, имеющая значения от 0 до 1, умножается на коэффициент усиления по напряжению, равный -5. Коэффициент имеет отрицательное значение, поскольку на катод светодиода необходимо подать напряжение, меньшее, чем на анод.

Затем усиленный сигнал подаётся на блок GP-AD-24 DAC, который управляет встроенным модулем цифро-аналогового преобразования (ЦАП). Максимальное выходное напряжение ЦАП составляет ±10 В, однако рабочее напряжение гирлянды — 100 В. Поэтому гирлянда подключается к КПМ РИТМ через усилитель Ponovo PA460Bi, который усиливает выходное напряжение с ЦАП в 20 раз. Гирлянда состоит из двух цепочек светодиодов с общим анодом, подключённым к земле, а на катоды подается отрицательное напряжение.

Схема подключения гирлянды:

image.png

Ниже представлен скрипт для обработки аудиофайла в формате WAV. В скрипте выполняются следующие действия:

  1. Загрузка необходимых библиотек;
  2. Чтение аудиофайла;
  3. Извлечение данных;
  4. Разряжение данных к шагу 0,01 с;
  5. Нормализация амплитуды;
  6. Степенная компрессия для усиления слабых значений амплитуды;
  7. Экспоненциальное сглаживание;
  8. Нормализация после сглаживания.
In [ ]:
using Pkg
!("FileIO" in [p.name for p in values(Pkg.dependencies())]) && Pkg.add("FileIO");
using Plots
using FileIO

# Чтение WAV файла с помощью FileIO
file_path = "$(@__DIR__)/nina-brodskaja-zvenit-janvarskaja-vjuga.wav"
audio = FileIO.load(file_path)

# Распаковка возвращаемого кортежа
audio_data, fs, num_channels, metadata = audio

# Шаг в 0.01 секунд
desired_step = 0.01  # Время между сэмплами в секундах

# Рассчитываем количество сэмплов для 0.01 секунды
desired_samples = round(Int, fs * desired_step)  # Количество сэмплов для 0.01 секунды

# Разряжение данных: выбираем каждое desired_samples-е значение
downsampled_audio = audio_data[1:desired_samples:end]

# Пересчитываем время (в секундах) для разреженных данных
t = (0:length(downsampled_audio)-1) * desired_step

# Нормализуем амплитуду
normalized_audio = abs.(downsampled_audio) ./ maximum(abs.(downsampled_audio))

# 1. Усиленная компрессия для слабых значений (с использованием степени < 1)
function enhance_weak_values(data, exponent, min_val, max_val)
    # Нормализуем данные в диапазоне от 0 до 1
    normalized_data = (data .- minimum(data)) ./ (maximum(data) - minimum(data))
    
    # Применяем степенную компрессию с показателем < 1 для усиления слабых значений
    enhanced_data = normalized_data .^ exponent
    
    # Масштабируем в диапазон от min_val до max_val
    compressed_data = min_val .+ enhanced_data .* (max_val - min_val)
    
    return compressed_data
end

# Применение усиленной компрессии для слабых значений (с exponent < 1)
exponent = 0.2  # Чем меньше значение, тем сильнее усиление слабых значений
compressed_audio = enhance_weak_values(abs.(downsampled_audio), exponent, 0, 1.0)

# ——————————————————————————————
# 2. Экспоненциальное сглаживание для замедления изменений яркости
function exponential_smoothing(data, alpha)
    smoothed = [data[1]]  # Начинаем с первого значения
    for i in 2:length(data)
        push!(smoothed, alpha * data[i] + (1 - alpha) * smoothed[end])
    end
    return smoothed
end

# Применяем экспоненциальное сглаживание с коэффициентом сглаживания 0.1 (замедляем изменения)
alpha = 0.2  # Чем меньше alpha, тем медленнее изменения
exponentially_smoothed_audio = exponential_smoothing(compressed_audio, alpha)
normalized_audio = normalized_data = abs.(exponentially_smoothed_audio .- 0.2) ./ (maximum(exponentially_smoothed_audio) - minimum(exponentially_smoothed_audio) - 0.2)

# Построение графика
gr()
plot(t, normalized_audio, title="Нормализованная амплитуда", xlabel="Время (с)", ylabel="Амплитуда", legend=false)
Out[0]:
No description has been provided for this image

Переменные t и normalized_audio загружаются в модель с помощью блока Табличная функция одной переменной в подсистеме Звуковой сигнал. После подключения гирлянды к КПМ РИТМ и обработки аудиофайла получается такой результат:
Гирлянда.gif

Полное видео работы: