Подробнее про теорему Котельникова и дискретизацию сигналов

Теорему Котельникова я уже вскользь упоминал в статьях про интерполяцию и синтез гитарного звука. Сегодня чувствую в себе силы углубиться в тему по-полной, буквально нырнуть с головой.

Чтобы никого не обидеть, теорему эту называют теоремой Котельникова — Найквиста — Уиттакера — Шеннона, или попросту теоремой отсчётов (the Sampling theorem). Она считается одним из важнейших результатов теории информации.

Формулировка достаточно простая:

Если аналоговый сигнал не содержит в своем спектре частот выше Fmax, то его можно идеально точно восстановить по дискретным отсчётам, взятым равномерно с частотой строго большей 2·Fmax.

Даже если вы не имеете никакого отношения к обработке сигналов, очень может быть, что вам знакома фраза “CD quality 44100 Hz”. Имеется в виду, что на компакт-дисках звук хранится в виде дискретных отсчётов, по 44100 штук на секунду. А это, согласно озвученной теореме, означает что “на CD можно идеально записать звук с частотой до 22050 Гц”, что вполне себе хорошо, так как слышимый человеком диапазон укладывается в эти рамки.

Казалось бы, всё отлично, что тут ещё обсуждать. Но у меня возник ряд вопросов:

  1. Ограниченность по частоте — так ли это просто, как кажется на первый взгляд?

  2. Как именно предполагается восстанавливать сигнал, чтобы получилось “идеально точно”?

  3. Что будет, если в оцифровываемом сигнале окажутся частоты равные или превосходящие допустимую половину частоты дискретизации? Они проигнорируются, или произойдет что-то другое?

В процессе поиска ответов я углублялся в детали, а оттуда сверкал глазами скрывающийся в них дьявол.

Должен предупредить, будет много страшной математики…

Читать далее ▸


Фурье-анализ и аддитивный синтез звука струны акустической гитары

Несмотря на академическое название, тут не будет интегралов и всяких этих “из последней жуткой формулы очевидно”. Тут будет несколько цветастых графиков, немного кода на C# и мои попытки доходчиво объяснить сложные вещи.

О чем пойдет речь

Эта статья — продолжение моего предыдущего эксперимента, где я, вооружившись Adobe Audition, разбирал на мелкие запчасти запись звучания моей гитары. Там я все делал на глазок, а теперь хочу с помощью точных расчетов проследить характер звучания нескольких первых гармоник, попробовать их приблизить более-менее простыми функциями и на основании полученных данных синтезировать гитарный звук.

План

  • С помощью дискретного преобразования Фурье (ДПФ) я соберу статистику об амплитудах гармоник. Обсужу интерпретацию результатов ДПФ.

  • Используя какую-нибудь интерполяцию приближу закон убывания амплитуд и попробую найти какие-нибудь закономерности. Вдруг они есть?

  • Аддитивным синтезом сгенерирую звук гитары, и, может быть, даже сыграю им небольшой музыкальный фрагмент.

Читать далее ▸


Backup сервера прямо в Яндекс.Диск

В предыдущих двух статьях я настраивал LAMP на VPS и прикручивал к нему nginx. Следующее, о чем сразу начинаешь думать — как бы все это не потерять. То есть речь заходит о резервном копировании.

Обсудим по порядку: что, куда и как бэкапить.

Читать далее ▸


PHP SQLite case-insensitive LIKE for Unicode strings

Official SQLite docs state:

SQLite only understands upper/lower case for ASCII characters by default. The LIKE operator is case sensitive by default for unicode characters that are beyond the ASCII range.

It’s the major inconvenience in using SQLite. Googling for a solution gives links to a lot of discussions, especially about enabling a certain ICU extension.

I am here to give you a complete answer to the question How to make the LIKE operator case-insensitive for UTF-8 strings when using SQLite via PHP PDO:

$pdo = new PDO("sqlite::memory:");

# BEGIN

function lexa_ci_utf8_like($mask, $value) {
    $mask = str_replace(
        array("%", "_"),
        array(".*?", "."),
        preg_quote($mask, "/")
    );
    $mask = "/^$mask$/ui";
    return preg_match($mask, $value);
}

$pdo->sqliteCreateFunction('like', "lexa_ci_utf8_like", 2);

# END

$pdo->exec("create table t1 (x)");
$pdo->exec("insert into t1 (x) values ('[Привет España Dvořák]')");

header("Content-Type: text/plain; charset=utf8");
$q = $pdo->query("select x from t1 where x like '[_РИ%Ñ%ŘÁ_]'");
print $q->fetchColumn();

The main idea is to override the default implementation of the LIKE function by using the PDO::sqliteCreateFunction call. It’s what the official FAQ suggests.

Advantages:

  • it works
  • no need to recompile anything

Disadvantages:

  • it’s obviously slower than the native implementation
  • The PDO::sqliteCreateFunction method is currently marked experimental

Anyway, I hope this post will help you.