Pull to refresh

Comments 37

Если решение и есть, то период уходит далеко в века.

Нужна пояснительная бригада. На непосвященный взгляд кажется, что 1 секунды достаточно. Ведь частоты целочисленные (в Герцах), значит в секунду укладывается целое число периодов. Или имелось в виду, что по сравнению с памятью микроконтроллера (не нашел упоминания модели в статье) секунда так же велика, как века?

И, похоже, без специальных ухищрений меньший период не годится, т.к. 1336 и 941 не имеют общих делителей.

Или имелось в виду, что по сравнению с памятью микроконтроллера (не нашел упоминания модели в статье) секунда так же велика, как века?

Да. У меня микроконтроллер nrf5340 + куча софта в прошивке уже есть. Ему даже полсекунды не запомнить на Fs 48kHz.

Отвечаю на вопрос о системе уравнений:

Никто не держит дискретизированные дтмф- последовательности в памяти.

Д в слове дтмф означает 'дуал', т.е. то, что синусов в сигнале два. Микросхема ДТМФ генератора умеет генерировать каждый из синусов в отдельности. Делает она это путем проигрывания записанных сэмплов, расчитывает сэмплы на лету или вообще генерирует их аналоговым способом - сказать сейчас не готов (потому что пишу с телефона).

Так или иначе, система не решается у вас из-за того, что сигналы дискретизированы по времени. Т.е. почти любое обрезание по времени приведёт к потере непрерывности сигнала, а значит к появлению в спектре выходного сигнала мусора - внеполосных сигналов.

Если так хочется решить задачу (и найти период, начиная с которого сигнал похож сам на себя) - посчитайте автокорреляционную функцию и найдите сдвиг, дающий пик автокорреляции. Проблема может быть в том, что чем длиннее вы будете брать запись, на которой будете считать xcorr, тем более подходящие пики автокорреляции будете находить каждый раз. Точного попадания, возможно, не добъетесь никогда (потому что частота дискретизации не кратна частотам всех 8 синусов, которые есть в ДТМФ).

А вообще, вы уже чуть-чуть прикоснулись к ЦОС (DSP) пытаясь решить эту задачу. Добро пожаловать. Тут очень интересно и очень многое неочевидно. Товарищи Смит и Лайонс с нетерпением ждут возможности всё вам рассказать и объяснить (правда русский перевод Смита содержит довольно много ошибок и неточностей перевода, а Лайонса днём с огнём не найти - но pdf-ки в сети есть).

Никто не держит дискретизированные дтмф- последовательности в памяти.

Я их тоже не держу. Рассчитываю в run-time аудиодорожку и отправляю на исполнение.
Потом эту же RAM паvять заполняю расчетами для другого тона и тоже отправляю на исполнение. RAM память пере используется.

А вообще, вы уже чуть-чуть прикоснулись к ЦОС (DSP)

Задумался, кстати, а какой спектр получится в результате проделанной тс операции - вырезания просчитанного куска на примерно 10 мс и его бесконечного повторения. В голове крутится что-то типа свёртки спектра прямоугольного сигнала частотой 100Гц (то есть sinc) и спектра исходного двухтонального сигнала, так как проделанное чем-то похоже на фазовую модуляцию. Но вот как это аналитически посчитать - ума не приложу. Разве что численно в вольфраме или матлабе считать. Нет идей? :)

Микроконтроллер в состоянии подсчитывать dtmf на лету, из одной небольшой таблицы синуса. Я делал это на 4- х битном контроллере на 400 килогерц в 95 году. Из каждой частоты вычисляете период с запасом в пару бит . Итого 3 сложения, два сдвига вправо и два LUT на отсчет.

То есть сегодня справится любой современный контроллер.

Да. Я тоже рассчитываю дорожки в run-time по формуле сложения синусов.

Надо воспроизвести тестовый звук. Что-нибудь предельно простое, например синус функцию. Затем измерять частоту и сравнить измеренную частоту с воспроизведенной частотой. Если значения совпали, то значит акустическая система воспроизведения работает четко

Генерируемая частота и её значение зависят только от микроконтроллера, который её генерирует. "Акустическая система воспроизведения" на это никак не влияет.

Вот таблица предварительно рассчитанных в RAM памяти микроконтроллера PCM семплов

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

Если решение и есть, то период уходит далеко в века

Как уже было справедливо указано - все частоты целые, поэтому период в любом случае не может быть больше 1 сек

В микроконтроллере по-любому не хватит никакой памяти, чтобы сохранить дорожку размером в период для суммы синусов с разрешенными частотами

16 вариантов по 1 сек. При частоте семплирования 32кГц и разрядности 16 (дикий оверкилл, на самом деле) получаем 1МБ. А если вспомнить, что вторая половина каждого записи ровно симметрична первой половине, до 512кБ. Для современных контроллеров вполне терпимо.

Но. В любом случае это решение в лоб и так не делают. А делают синтез по таблице.

То есть имеем одну единственную таблицу для значений синуса от 0 до 90 градусов. Как показывает практика обычно 64 точки более чем достаточно. То есть получаем 256 точек на период.

Для каждой генерируемой частоты имеем аккумулятор, который для каждого следующего выходного семпла увеличивается на величину:

генерируемая частота / частоту дискретизации * количество семплов в таблице

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

Повторяем для всех частот, которые надо сгенерировать, суммируем полученные значения и выдаём на выход.

Всё, простейший табличный синтез.

Да, я знаю, что аккумулятор может быть целочисленный и так даже удобнее.

Просто не стал уже вдаваться в детали :)

"Акустическая система воспроизведения" на это никак не влияет.

У звукоизлучателя может быть порвана мембрана.

От этого генерируемая частота не изменится. Максимум появятся гармоники.

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

Сложность в том, что мне надо на лету менять еще и sample rate: 8kHz, 16kHz, 32kHz, 41kHz, 50kHz, 48kHz, 98kHz, 128kHz.

Слишком много таблиц получится.

Если мы говорим о вашем алгоритме "в лоб", то вам нужно считать ровно столько же таблиц. Только если хранить в памяти только участок 0-90 градусов, то требования к памяти можно уменьшить в 4 раза.

Если же говорить об алгоритме синтеза по таблице, то предпросчитанная таблица к частоте дискретизации не привязана никак вообще. От частоты дискретизации зависит только величина инкремента аккумулятора. Поэтому таблица всего одна для любой частоты.

https://web.archive.org/web/20120308235958/http://www.ied.com:80/~petr/Oscillators.html#Second Order Oscillator

для генерации непрерывного синуса он считается за одно единственное умножение на отсчёт, без таблиц вообще, надо только заранее посчитать три коэффициента которые задают частоту, амплитуду и фазу.

Спасибо!
В моём тексте трудность не сколько в скорости расчета синуса сколько в том, что мало памяти, чтобы сохранить звуковую дорожку на воспроизведение.

так его вообще не надо хранить если он считается за одно целочисленное умножение.

Любопытная схема. Надо будет помоделировать - пока не изучал детально, поэтому что-то не очень понимаю как считать коэффициенты и насколько устойчив будет алгоритм к самовозбуждению (особенно при использовании коэффициентов).

Y[n+1] = K*Y[n] - Y[n-1]

K = 2*cos(f/Fs)

Y[-1] - задаёт начальное значение выхода осциллятора

Y[0] - значение в следующий момент времени, вместе с частотой и предыдущим значением задаёт амплитуду.

если первое значение Y[-1] сделать 0

то записав во второе значение Y[0] = А

считая дальше значения как Y[n+1] = K*Y[n] - Y[n-1] получится синус с нулевой фазой и амплитудой A/sin(f/Fs).

в отличии от умножения {0,1} на матрицу повотора который копит ошибку, этот осциллятор устойчив даже в целых числах.

  1. Частоты DTMF подобраны так не кратно потому, чтоб не вызывать ложных срабатываний при прохождении тонов через тракт с существенной нелинейностью.

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

Я на ATTINY-85 делал FFT 8bit с целочисленным LUT для sin/cos и она занимала памяти совсем чуток (нужно только до 45 градусов хранить) причём одна и для sin и для cos - все выводится отлично на ходу - вообще никаких проблем.

По моему для ЛЮБОГО числа одновременно работающих генераторов достаточно иметь таблицу синусов (точнее, её четверть) и набор счётчиков с соответствующими периодами.

Суммируем их мгновенные значения и получаем значение для шим. Бонусом, тут можно домножать значения для того что бы частоты были с разными уровнями.

При этом, чем выше частота тактирования счётчиков и ШИМ, тем чище будет звук, ибо именно на этой частоте сойдутся кратности выходных частот.

Если решение и есть, то период уходит далеко в века.

В музыке это называлось «полиритм» т.е. в 1 такте проигрывался один звук 5 раз, а второй 4. То есть как минимум их произведение дает полный цикл

Есть такой мем, что самое сложное для понимания инженеров - это нотная грамота.

Это задача по арифметике, а не по теории музыки. Если периоды двух сигналов равны t1 и t2 и отношение t1/t2 рационально, то общий период равен НОК(t1,t2). НОК вычисляется как произведение периодов t1*t2, делённое на их НОД.

Если отношение t1/t2 иррационально, то алгоритм Евклида будет выполняться бесконечно долго. Но можно разложить t1/t2 в цепную дробь, значения которой будут всё точнее приближать требуемое отношение. Самое интересное, что так можно аппроксимировать не только иррациональное, но и "сложное" рациональное число более "простой" дробью (с меньшим знаменателем).

Для числа 1336/941 получаем приближения 1, 3/2, 7/5, 10/7, 17/12 и т. д.

Теория цепных дробей всё же имеет отношение к музыке - она хорошо описывает периодические паттерны, которые человек слышит в одновременно звучащих тонах (или ритмах), или видит в наложенных периодических решётках (муар) и т.д.

Что-то я не понимаю.

Есть ли возможность явно написать какой же будет период (в секундах) у суммы синусов с частотами 1336 Hz и 941 Hz?

НОД(1336 Hz, 941 Hz) = 1 Hz.
Т.е. период будет 1 секунда.

Но, насколько я вижу в Q.23, для DTMF допускается отклонение частоты до 1,8 %. Т.е. можно использовать, например, частоты 1330 Гц и 950 Гц. Для них НОД(1330 Гц, 950 Гц) = 190 Гц. Т.е. период будет 1/105 Гц ~= 5,26 мс. В него будут укладываться 7 периодов верхней частоты и 5 периодов нижней.

1/105 Гц

Опечатка. Читать как 1/190 Гц.

Поиск периода суммы синусов через решение линейного диофантова уравнения

Можно подойти к задаче с другой стороны. Период суммы синусов это, в сущности, целое число периодов высокой частоты f1 и другое целое число периодов на низкой частоте f2. Эти произведения периодов должны совпадать как показывает уравнение (5)

\\  \frac{N}{f_1 } = \frac{M}{f_2}  \;\;\;\;\;\;\;\;\; (5)

Уравнение (5) вырождается в уравнение (6). А уравнение (6) это не что иное как линейное диофантово уравнение

\\ \frac{N}{f_1 } - \frac{M}{f_2} =0  \;\;\;\;\;\;\;\;\;\;\;\;\; (6)

Можно найти период суммы синусов, если решить линейной Диофантово уравнение (6). Сделать это можно перебором. Только тут сразу стоит сказать, что обходить матрицу чисел NxM надо зигзагом по диагонали, начиная от верхнего левого угла. Так численный алгоритм быстрее наткнется на решение.

Одно из решений уравнения (6) можно просто угадать. Если каждый период умножить на его частоту, то получается 1 секунда. Однако в микроконтроллере по-любому не хватит никакой памяти, чтобы сохранить дорожки размером в 1 секунду для для всех 16 тонов и всех частот дискретизации. Такая дорожка для 16-битного звука в 2х канальном I2S на частоте 48kHz заняла бы 187.5kByte RAM памяти.

для DTMF допускается отклонение частоты до 1,8 %

Если период 1 с кажется большим, то можно поискать более короткие периоды с помощью аппроксимации цепными дробями:

1336/941 ≈ 1,419766206163655685... ≈ {1; 3/2; 7/5; 10/7; 17/12; 27/19; 44/31; 71/50; 115/81; 1336/941}.

Из этих аппроксимаций 7/5 уже даёт достаточную точность (ошибка составляет 1,4%). Поэтому можно взять ближайшие удобные числа, дающие соотношение 7/5, например, 1330 и 950 Гц. 1330=190*7. 950=190*5. Общий период будет равен 1/190 ≈ 5,26 мс.

А вообще, применительно к теме, если частота сигнала заранее неизвестна, лучше вычислять синус по таблице (см. раз, два, три).

ну чтож, автор открыл для себя "хорошо забытое старое", и навесил кликбейтный заголовок.

Для меня вот например вполне себе "открытием" здесь является картинка с синусом и треугольником - я вполне знаю про ШИМ, но у меня в голове это представление сугубо "машинное" в виде счетчика. Хотя даже в даташитах значение счетчиков треугольниками рисуют.

Задача образования не только в производстве новых знаний, но и в воспроизводстве старых.

Если вы воспроизводите синус, то вы осциллографом не увидите синус на выходе. Вы его только услышите. Надо еще прикрепить специально рассчитанный фильтр нижних частот.

Пользуйтесь цифровым осциллографом - даже у дешёвых есть настраиваемые ФНЧ/ФВЧ, которые программно удаляют постоянную составляющую и ВЧ-помехи от ШИМа.

Вообще не понимаю, зачем ехать в Париж через Чукотку. Засэмплировать по одному периоду отдельных частот и смешивать одну частоту из «нижней» группы с одной из «верхней» группы «на лету». Один цикл while с двумя циклическими счётчиками и одна операция сложения. «Когда деревья были большими» с этим справлялись 8-битные МК с частотой ядра 4МГц ) - правда, если писать на ассемблере ))

А то, что «наименьший общий период» будет «стремиться к бесконечности» - очевидно, там частоты специально подобраны так, чтобы гармоники одной не попадали на другую.

Засэмплировать по одному периоду отдельных частот

Этот подход плохо работает когда частота дискретизации не слишком велика. Например, 1633Гц при частоте дискретизации 32кГц даст всего 20 семплов на период. То есть фактическая частота сгенерированного сигнала будет 32/20=1.6 кГц. В случае DTMF это не критично, но метод табличного синтеза с интерполяцией не сильно сложнее вычислительно, но даёт куда более точное значение синтезированной частоты.

Классная статья, спасибо. Но слишком уж много опросов в конце, пока долистаешь чтобы поставить плюс устанешь.

Sign up to leave a comment.

Articles