реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Помогите опознать алгоритм
ataradov
сообщение Oct 9 2011, 19:33
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Помогите опознать алгоритм пожалуйста.

Для размерности 3 выглядит вот так:

CODE
      a0[0] = a[1] * a[2];
      a0[1] = b[1] * a[2] + a[1] * b[2];
      a0[2] = b[1] * b[2];

      a0[0] += a[0] * a[2];
      a0[1] += b[0] * a[2] + a[0] * b[2];
      a0[2] += b[0] * b[2];

      a0[0] += a[0] * a[1];
      a0[1] += b[0] * a[1] + a[0] * b[1];
      a0[2] += b[0] * b[1];


a, b - исходные векторы размерности 3, a0 - результат.

В коде видны явные закономерности, похоже на какую-то стандартную операцию над векторами, но не могу понять какую именно.
Go to the top of the page
 
+Quote Post
iiv
сообщение Oct 9 2011, 20:40
Сообщение #2


вопрошающий
*****

Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436



Пусть у Вас есть матрица сдвига P

(0 1 0)
(0 0 1)
(1 0 0)

a и b - векторы, тогда матрица H=
( a, b ) ^T P ( a, b )
на диагонали будет содержать a0 и a2, а сумма внедиагональных членов будет равна a1.

Сам такое много раз и в уравнениях Максвелла встречал, и в сигнал процессинге. Расскажите побольше про задачу, может удастся разобраться откуда уши ростут.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 10 2011, 12:11
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Вот более полный код, для N=3 эквивалентен вышеприведеному, за исключением посленей части:
CODE
  for (int k = 0; k < N; k++)
  {
    a1[0] = 1.0; a1[1] = a1[2] = a1[3] = 0.0;

    for (int j = 0; j < N; j++)
    {
      if (j == k)
        continue;

      a1_old = 0.0;
      for (int i = 0; i < N+1; i++)
      {
        t = a1[i] * a[j] + a1_old * b[j];
        a1_old = a1[i];
        a1[i] = t;
      }
    }

    for (int i = 0; i < N+1; i++)
      a0[i] += a1[i];
  }

  a1_old = 0.0;
  for (int i = 0; i < N+1; i++)
  {
    t = a1[i] * a[N-2] + a1_old * b[N-1];
    a1_old = a1[i];
    a1[i] = t;
  }
Это кусок мат. модели, векторы a и b вычисляются из физических параметров системы.

После этого из массивов а0 и a1 формируются коэфициенты полинома (комплексные):
CODE
  for (int i = 0; i < N+1; i++)
  {
    c[i].real= t0 * a1[i];
    c[i].imag = t1 * a1[i];

    if (i > 0)
      c[i].imag -= a0[i-1];
  }
t0 и t1 - тоже вычисляются из параметров, представляют собой выражения вида t0 = A * sin(W), t1 = A * cos(W).

После этого находятся корни полинома, и они используются дальше в модели.

Сообщение отредактировал Taradov Alexander - Oct 10 2011, 12:14
Go to the top of the page
 
+Quote Post
iiv
сообщение Oct 10 2011, 14:52
Сообщение #4


вопрошающий
*****

Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436



a1 инициализирован только в первых 4 элементах. А дальше, в общем случае, тоже нули или модель просто не гоняли? Циклы в общем случае по i,j,k всегда до одного и того же N бегут? С виду очень походе на линейное предсказание с преобразованием исходных реальных векторов в комплексные, но и на сто процентов сказать не могу, если есть еще какая-то информация об алгоритме, говорите!
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 10 2011, 15:10
Сообщение #5


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



QUOTE (iiv @ Oct 10 2011, 18:52) *
a1 инициализирован только в первых 4 элементах. А дальше, в общем случае, тоже нули или модель просто не гоняли?
Да, нули. Но в жизни он будет использоваться только с 2 и 3 элементами.

QUOTE (iiv @ Oct 10 2011, 18:52) *
Циклы в общем случае по i,j,k всегда до одного и того же N бегут? С виду очень походе на линейное предсказание с преобразованием исходных реальных векторов в комплексные, но и на сто процентов сказать не могу, если есть еще какая-то информация об алгоритме, говорите!
Да, до одного (иногда до N, иногда до N+1).

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

Вот код инициализации a[] и b[]:
CODE
  avg = 0.0;
  for (int i = 0; i < N; i++)
    avg += arr[i];
  avg = avg / N;

  a[N] = b[N] = 0.0;
  for (int i = 0; i < N; i++)
  {
    a[i] = (2.0 - arr[i] / avg) / (2.0 * avg);
    b[i] = (1.0 - arr[i] / avg) * overtone * M_PI;
  }

Тут arr[] - массив немного отличающихся частот, имитация 3 немного расстоенных струн в хоре одной клавиши, похоже. overtone - номер текущего обертона.

На выходе (после нахождения корней полинома) получается 3 комплексных числа, действительная часть которых деленная на 2*pi равна "настоящему" (тому что используется непостредственно при синтезе) смещению частоты от центральной (частоты ноты), а мнимая - напрямую скорости затухания струны (показателю экспоненты).

Массив arr[] получается путем сравнительно сложных табличных преобразований, но это не важно, можно просто считать, что он содержит числа примерно равные частоте струн данной ноты, с небольшой расстройкой. Расстройка растет с номером гармоники, на выходе получается похожая расстройка (тоже растет с номером гармоники), но большая по абсолютной величине.

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

PPS: В худшем случае я просто выкину все эти пробразования, заменив их на таблицы/аппроксимации, но интересно будет понять что-же тут происходит, может когда пригодится еще.

Сообщение отредактировал Taradov Alexander - Oct 10 2011, 15:43
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 11 2011, 06:12
Сообщение #6


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Немного становится понятнее. В цикле тут происходит перемножение полиномов. Начальный полином - это константа 1. после чего он домножается на (b[j] x + a[j]), где j != k. и результат складывается.

Теперь нужно понять какой в этом физический смысл.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 11 2011, 16:19
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Вот эквивалентный код на Matlab-e:
CODE
arr = [261.4508114 261.5063567 261.6451613];
avg = sum(arr) / length(arr);

a = (2.0 - arr / avg) / (2.0 * avg);
b = (1.0 - arr / avg) * (1) * pi;

az1 = conv([1.0, 0.0], [a(2) b(2)]);
az1 = conv(az1, [a(3) b(3)]);

az2 = conv([1.0, 0.0], [a(1) b(1)]);
az2 = conv(az2, [a(3) b(3)]);

az3 = conv([1.0, 0.0], [a(1) b(1)]);
az3 = conv(az3, [a(2) b(2)]);

a0 = az1+az2+az3;

a1 = conv(az3, [a(2) b(3)]);

tt0 = 222.9164178;
tt1 = -1.571716919;

for i = 1:4,
  z(i) = tt0 * a1(i) + j*(tt1 * a1(i));
  if i > 1,
    z(i) = z(i) - j*a0(i-1);
  end;
end;

r = roots(z);


Интересное наблюдение - если в arr все числа одинаковые, то два корня полинома z равны нулю, а один не равен, именно он определяет частоту и скорость затухания. То-есть вся эта процедура стремится распределить скорости затухания по струнам так, чтобы имитировать двухстадийное затухание (резкий спад, потом плавное затухание), присущее настояшему музыкальному инструменту.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 11 2011, 20:53
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Нашел статью, в которой используется похожий подход. Этот код строит передаточную функцию системы и ищет ее полюсы. Из полюсов автоматически находятся нужные параметры.
Go to the top of the page
 
+Quote Post
iiv
сообщение Oct 12 2011, 15:09
Сообщение #9


вопрошающий
*****

Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436



Цитата(Taradov Alexander @ Oct 12 2011, 02:53) *
Нашел статью, в которой используется похожий подход. Этот код строит передаточную функцию системы и ищет ее полюсы. Из полюсов автоматически находятся нужные параметры.

Добый день, Александр,

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

С уважением

ИИВ
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 12 2011, 18:10
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



LP - это линейное программирование?

Если что, вот статья про которую я говорю: https://ccrma.stanford.edu/~stilti/papers/rltalk.pdf

Вот немного более читаемый матлабовский код:
CODE
clear all;

arr = [261.4508114 261.5063567 261.6451613];
avg = sum(arr) / length(arr);

t = 1 - arr / avg;
a = (t+1) / (avg * 2);
b = t * (1) * pi;

az1 = conv(conv([1.0, 0.0], [a(2) b(2)]), [a(3) b(3)]);
az2 = conv(conv([1.0, 0.0], [a(1) b(1)]), [a(3) b(3)]);
az3 = conv(conv([1.0, 0.0], [a(1) b(1)]), [a(2) b(2)]);

a0 = az1+az2+az3;
a0 = [0 a0];

a1 = conv(az3, [a(2) b(3)]);

t0 = 199.1735851;
t1 = -0.00705058376;

z = t0 * a1(1:4) * exp(j*t1) - j*a0(1:4);

r = roots(z);

В результате
CODE
r =

  -0.0568 + 7.8407i
   0.3645 + 0.0279i
  -0.3631 + 0.0056i
что полностью согласуется с выводами в статье - получилось 3 "струны", одна затухает очень быстро (7.8407), а две остальные медленно (0.0279 и 0.0056) при этом они расстроены по частоте так, что образуются биения.

Я с корневыми годографами на "вы", так что осознать пока все это не могу, но похоже, что t1 - это то, что в статье обозвано коэффициентом связи (coupling coefficient). В параметрах модели он плавно меняется от 0 до -15 градусов (тут он переведен в радианы уже) при изменении номера клавиши от первой до последней.
Go to the top of the page
 
+Quote Post
iiv
сообщение Oct 15 2011, 19:30
Сообщение #11


вопрошающий
*****

Группа: Свой
Сообщений: 1 726
Регистрация: 24-01-11
Пользователь №: 62 436



Я думал, что линейное предсказание, но, похоже, ошибался.

Если представить $a_i$, $b_i$ как входные векторы, то результат в матричном виде и латехе можно записать примерно так:

$$\left( \product_i (a_i I + b_i P) \right) \sum_i (a_i I + b_i P)^{-1} e,$$

где $e = (1, 0, ..., 0)^T$, а P матрица сдвига, как я сказал выше.

Правда мне такое представление ничего не дало чтобы упростить или как-то серьезно перекаверкать этот алгоритм...
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 15 2011, 19:47
Сообщение #12


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Похоже и не получится, похоже, что это результат не матричных операций. Плохо, что не ясен даже физический смысл a[], b[], t0 и t1.

В любом случае я продолжаю читать разные статьи и пробовать разные варианты, возможно получится решить задачу самостоятельно и другим методом.
Go to the top of the page
 
+Quote Post
ataradov
сообщение Oct 19 2011, 16:07
Сообщение #13


Профессионал
*****

Группа: Участник
Сообщений: 1 014
Регистрация: 8-01-07
Из: San Jose, CA
Пользователь №: 24 202



Продолжаю ковырять этот алгоритм. Начал его исследовать как черный ящик. На картинке изображены графики действительной части решений при фиксированных arr и t1 и изменяющемся t0.

Похоже, что решение состоит из комбинации экспонент (как минимум 4 штуки на 1 график).

PS: на изменение цвета линии внимание можно не обращать - это просто корни меняются местами.
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 05:22
Рейтинг@Mail.ru


Страница сгенерированна за 0.01516 секунд с 7
ELECTRONIX ©2004-2016