Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Изменение фазы сигнала.


Автор: ivan219 12.11.2008, 16:56
Собственно вопрос вот в чём уменя есть два сигнала полученых с LinIn разность фаз которых равно 90 градусов но на самом деле там не совсем 90 вот надо както компенсировать это отклонение от 90 градусов. Как это сделать smile 

Автор: Alexeis 13.11.2008, 10:33
  В продолжении темы про фурье, комплексный спеткр можно представить в тригонометрической форме R(n) * e^(i * FI(n)) . Rn - длинна вектора имеющего начало в начале системы координат и концом в точке на комплексной плоскости с координатами (Re(n), Im(n)) для n-й частоты, FI(n) - угол вектора относительно оси Х. Форму  R(n) * e^(i * FI(n)) получается из R(n)*(Cos(FI) + i*Sin(FI)). Соответственно после перевода в тригонометрический вид нужно к углу F(n) добавить 90 градусов, тогда получим для m й частоты (2й частоты)
R(m)*(Cos(FI(n) + 90) + i*Sin(FI(n) + 90)), преобразуя к алгебраическому виду имеем 

Re(m) = R(m)*Cos(FI(n) + 90);
Im(m) = R(m)*Sin(FI(n) + 90);

Дальше если еще вспомнить тригонометрию, то Cos(FI(n) + 90) = - Sin(FI(n)), а Sin(FI(n) + 90) = Cos(FI(n)), в результате

Re(m) = - R(m)*Sin(FI(n));
Im(m) = R(m)*Cos(FI(n));

Напомню еще что R(m) вычисляется как Sqrt(Re(m)^2 + Im(m)^2), а 
FI(n) = arctTg(Im(n) / Re(n));

Итого окончательно имеем новые Re` и Im`

Re`(m) = - Sqrt(Re(m)^2 + Im(m)^2) * Sin(arctTg(Im(n) / Re(n)));
Im`(m) = Sqrt(Re(m)^2 + Im(m)^2) * Cos(arctTg(Im(n) / Re(n)));

Далее исправленные значения комплексного спектра записываем на место старых и делаем обратное преобразование фурье, в результате волны должны сместиться так что угол будет составлять 90 градусов.


Автор: ivan219 13.11.2008, 15:12
Спасибо. 
Но немного не то что я хотел.
Мне надо чтобы после фильтрации вот тут DuolChanal[I * 2] было по фазе 0 а здесь DuolChanal[I * 2 + 1] должно быть 90 на самом деле в нём после генератора 89 это для примера а надо сделать 90

Код

 F := 2 * 96000 / 1024;

 for I := 0 to 1023 do // Генератор
  begin
   DuolChanal[I * 2] := 4 * Sin(F * 2 * Pi * I / 96000 );
   DuolChanal[I * 2 + 1] := 4 * Sin(F * 2 * Pi * I / 96000 + 89 * Pi / 180);
  end;

 FastFourierTransform(DuolChanal, 1024, False); // FFT

 for I := 0 to 1023 do // Исправляем фазу
  begin
   FArcTan := ArcTan(DuolChanal[I * 2 + 1] / DuolChanal[I * 2]);
   FSqrt := Sqrt(Sqr(DuolChanal[I * 2]) + Sqr(DuolChanal[I * 2 + 1]));
   Buff := - FSqrt * Sin(FArcTan);
   Buff1 := FSqrt * Cos(FArcTan);
   DuolChanal[I * 2] := Buff;
   DuolChanal[I * 2 + 1] := Buff1;
  end;

 FastFourierTransform(DuolChanal, 1024, True); // FFT

 Canvas.MoveTo(100, 300 - Round(DuolChanal[0] * 20));
 for I := 1 to 1023 do Canvas.LineTo(I + 100, 300 - Round(DuolChanal[I * 2] * 20));

 Canvas.MoveTo(100, 500 - Round(DuolChanal[1] * 20));
 for I := 1 to 1023 do Canvas.LineTo(I + 100, 500 - Round(DuolChanal[I * 2 + 1] * 20));

Автор: Alexeis 13.11.2008, 15:19
  Тогда еще проще, просто вычислить амплитуду, подставить свою фазу и обратным фурье получить нужный сигнал.

Автор: ivan219 13.11.2008, 15:28
Цитата(Alexeis @  13.11.2008,  15:19 Найти цитируемый пост)
  Тогда еще проще, 

 smile 

Автор: ivan219 13.11.2008, 15:50
Alexeis, и ещё тут Re(m) = R(m)*Cos(FI(n) + 90); Im(m) = R(m)*Sin(FI(n) + 90); вот эти m и n их значение одинаково или нет.

Если я правильно понял то должно быть так:

Re(1) = R(1) * Cos(FI(1) + 90);
Im(1) = R(1) * Sin(FI(1) + 90);

Да???

Автор: Alexeis 13.11.2008, 17:44
 Гмм... чет я ничего не понял. Фаза 90 градусов относительно чего?

Автор: ivan219 13.11.2008, 20:20
Цитата(Alexeis @  13.11.2008,  17:44 Найти цитируемый пост)
 Гмм... чет я ничего не понял. Фаза 90 градусов относительно чего?

Есть массив DuolChanal размеров 2048.
Вот так он заполняется
Код

 F := Frequency * 96000 / 1024;

 for I := 0 to 1023 do // Генератор
  begin
   DuolChanal[I * 2] := 4 * Sin(F * 2 * Pi * I / 96000 );
   DuolChanal[I * 2 + 1] := 4 * Sin(F * 2 * Pi * I / 96000 + 90 * Pi / 180);
  end;

Внутри получается 2 сигнала:
0, 2, 4....2046 один сигнал с фазой 0 градусов. (F / 1024)
1, 3, 5....2047 второй сигнал с фазой 90 градусов. (F / 1024)

После чего делаем БПФ и теперь если менять частоту Frequency то всегда будит видно 1 отсчёт сночало положительной частоты от 0 до 48000 потом отрицательной частоты от -48000 до 0.

Вся соль в том чтобы второй сигнал был равный по амплитуде и отстовал на 90 градусов по сравнению с первым соответственно частоты тоже должны совподать т.е. надо A1 = A2; F1 = F1; Fi1 = Fi2 - 90;

Вся информация поступает с входа LinIn звуковой карты и несовсем в той форме какую надо вот и приходится программно коректироват амплитуду и фазу привости их к виду A1 = A2; F1 = F1; Fi1 = Fi2 - 90;

Автор: Alexeis 13.11.2008, 20:56
Цитата(ivan219 @  13.11.2008,  19:20 Найти цитируемый пост)
Вся соль в том чтобы второй сигнал был равный по амплитуде и отстовал на 90 градусов по сравнению с первым соответственно частоты тоже должны совподать т.е. надо A1 = A2; F1 = F1; Fi1 = Fi2 - 90;

  Воот, тогда то что я написал в начале как раз то что нужно  smile 

Автор: ivan219 14.11.2008, 16:09
Цитата(Alexeis @  13.11.2008,  20:56 Найти цитируемый пост)
Воот, тогда то что я написал в начале как раз то что нужно

Не совсем надо в нести некоторую по правку, унас 2 вектра крутятся и если все числа исправить так:
Re(m) = R(m)*Cos(FI(n) + Fi');
Im(m) = R(m)*Sin(FI(n) + Fi');
То получаем искажение.

Надо для положительной частоты делать так:
Re(m) = R(m)*Cos(FI(n) - Fi');
Im(m) = R(m)*Sin(FI(n) - Fi');
А для отрицательной:
Re(m) = R(m)*Cos(FI(n) + Fi');
Im(m) = R(m)*Sin(FI(n) + Fi');

И того имеем:
Код

 FastFourierTransform(DuolChanal2, 1024, False); // FFT
 for I := 0 to 1023 do  // Компенсация амплитуды и фазы
  begin
   FSqrt := Sqrt(Sqr(DuolChanal2[I * 2]) + Sqr(DuolChanal2[I * 2 + 1]));
   if DuolChanal2[I * 2] <> 0 then FArcTan := ArcTan(DuolChanal2[I * 2 + 1] / DuolChanal2[I * 2])
   else FArcTan := Pi / 2;
   if I < 512 then
    begin
     FCos := Cos(FArcTan - Kf * Pi / 180); // Kf - компенсация фазы
     FSin := Sin(FArcTan - Kf * Pi / 180);
    end
   else
    begin
     FCos := Cos(FArcTan + Kf * Pi / 180);
     FSin := Sin(FArcTan + Kf * Pi / 180);
    end;
   DuolChanal2[I * 2] := FSqrt * FCos * Ka; // FCos - компенсация по фазе Ka - компенсация по амплитуде
   DuolChanal2[I * 2 + 1] := FSqrt * FSin * Ka; // FSin - компенсация по фазе Ka - компенсация по амплитуде
  end;
 FastFourierTransform(DuolChanal2, 1024, False); // FFT

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

Какбы это обойти? Чтобы при основном БПФ происходила компенсация фазы и амплитыды.

Автор: Alexeis 14.11.2008, 16:36
Цитата(ivan219 @  14.11.2008,  15:09 Найти цитируемый пост)
единственно что плохо так это что нужно делать прямое и обратное БПФ второго сигнала для исправления амплитуды и фазы, а потом уже общее БПФ для двух.

  Это еще зачем? Если сделаешь общее БПФ, то на нем можно отдельно работать с каждой из составляющих спектра и менять фазу независимо для каждой волны.

Автор: ivan219 30.11.2008, 15:08
Финал.
Не всё оказалось так просто!!!
В архиве пример может кому пригодится.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)