Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Оцифровка сигнала [под управлением atmega]
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
zi4rox
ATMega16 управляет внешним АЦП TLV1570 по встроенному SPI и пытаемся оцифровать гармонический сигнал с частотами до 20кгц.

Немного о TLV1570 - 8ми канальный 10ти разрядный последовательный АЦП 1.25MSPS. Входные напряжения: 0 .. 5В

По теореме Котельникова, частота дискретизации: Fдиcкр > 2Fmax
В моём случае 2Fmax = 40кГц, а частота дискретизации АЦП по даташиту считается так: Fдискр = 1/16*Fsclk (на каждую выборку нужно передать 2 байта) (в обвязке к ATMega стоит резонатор на 16МГц, при настройках SPI получил: Fsclk = 4Mhz ) => Fдиск = 1\16*4Mhz = 250кГц

Т.е. мы укладываемся с головой. Частота дискретизации 250 кГц, а сигнал 20кГц

Код прошивки такой:
Код
while (1) {    
for (i=0;i<100;i++) {    
ADC_CS = 0;
adc_result_hi[i] = spi(0x00);
adc_result_low[i] = spi(0x60);  
ADC_CS = 1;      
}              

for (i=0;i<100;i++){
putchar(adc_result_hi[i]);        
putchar(adc_result_low[i]);        
}
}

* я сначала собираю отсчеты по 100 точек и сохраняю их в буффер, а затем отправляю по UART на COM порт в ПК. (так быстрее производительность, т.к. отправка по уарту занимает значительное время)

Просимулировал этот код в VMLAB, получил следующие тайминги:



С учетом всех погрешностей на запись в переменные и т.п - получил, что снятие одного отсчета займет 10мкс - т.е. частота дискретизации 100кГц - все равно укладываемся.

Итак, на практике вот что я получаю:

Оцифровка сигнала частотой 10кГц амплитуда около 1В:

Здесь около 10ти точек на период. Качество оцифровки неудовлетворительное.

Сразу же в настройках SPI выставил галочку SCLK x2 Rate - т.е. удвоили частоту тактирующего импульса (я предполагал что и качество оцифровки увеличится в 2 раза)

Вот как получилось с этой настройкой:

Оцифровка сигнала частотой 10кГц амплитуда около 1В (SPI SCLK x2 rate):


Получилось 13 точек на период - совсем небольшой прирост =(

Мучил код, пробывал и так и сяк, симулировал.
Вот как получается, если после получения отсчета от АЦП - сразу выплевывать его на UART:
Код
while (1) {    

ADC_CS = 0;        
putchar(spi(0x00));
putchar(spi(0x60));
ADC_CS = 1;    

}


Совсем не так как хотелось бы.

* Сигнал с меньшей частотой оцифровывает прелестно. Вот пример оцифровки синуса с частотой 1кГц:

Здесь меня всё устраивает. Около 90 точек на период. Качество отличное

Прошу помощи - оцифровкой занимаюсь в первый раз, как быть, вроде бы всё правильно - а на деле выходит совсем не то. Возможно код можно ещё как то более оптимизировать, или ещё где ошибку сделал? Прошу совета.
Petka
Цитата(zi4rox @ May 23 2009, 19:48) *
...
Т.е. мы укладываемся с головой. Частота дискретизации 250 кГц, а сигнал 20кГц
...


На вид все картинки у вас правильные. Разве что иногда у вас теряются отсчёты (видно на второй картинке "синуса").
Dx!
То вам "Fдиcкр > 2Fmax" А то 10 точек на период мало 8) Тогда и считайте частоту, отталкиваясь от минимально количества этих самых точек 8) Эти десять точек на период в 10КГц синусоиды.... уже 100Кгц дискретизации.

Мне собственно непонятно - что вам не нравится.

Цитата(Petka @ May 23 2009, 22:46) *
На вид все картинки у вас правильные. Разве что иногда у вас теряются отсчёты (видно на второй картинке "синуса").

Это имхо не потеря, а места склейки семплов по 100 точек.
Petka
Цитата(Dx! @ May 24 2009, 03:47) *
Это имхо не потеря, а места склейки семплов по 100 точек.

ага. похоже на то.
zi4rox
Да, сейчас тоже пересчитал - получается что ацп правильно работает - и там получается 10 точек на период. Буду пытаться увеличить частоту дискретизации каким то образом.

Непонятно пока - сколько этих точек на период в среднем необходимо для более менее верной оцифровки? Или это определяется исходя из личных условий задачи? Вы как считаете?
Petka
Цитата(zi4rox @ May 24 2009, 12:41) *
Непонятно пока - сколько этих точек на период в среднем необходимо для более менее верной оцифровки? Или это определяется исходя из личных условий задачи? Вы как считаете?

Верной для чего?
Чтобы измерить частоту? Амплитуду? С какой точностью?
P.S.
В хороших цифровых осциллографах частоту дискретизации выбирают в 10 раз большую, чем максимальная наблюдаемая. В дешёвых от 2х раз. Правда там ещё дополнительно применяют цифровую интерполяцию. Для наблюдения синуса достаточно хорошо подходит "sin(x)/x correction".
zi4rox
Измерять нужно амплитуду. Про цифровую интерполяцию интересно! Пойду искать информацию по этой теме, спасибо за идею.

* Если кто нибудь знает хорошую ссылку на алгоритм/или мат. описание интерполяции sinc(x) прошу поделится
smac
Цитата(zi4rox @ May 24 2009, 13:37) *
Измерять нужно амплитуду. Про цифровую интерполяцию интересно! Пойду искать информацию по этой теме, спасибо за идею.

* Если кто нибудь знает хорошую ссылку на алгоритм/или мат. описание интерполяции sinc(x) прошу поделится

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

Вот формула, для восстановления сигнала:



x(t) - исходный сигнал
Fmax - частота сигнала, пусть Fmax = 1000 Гц
dt = 1/2Fmax (отсчеты идут через этот интервал времени) dt = 1/2*1000 = 0.0005

При это допустим что ацп выдает нам 13 отсчетов сигнала на период. Сам же период T = 1/f = 0.001. Вот на интервале времени в 1 период я и хочу восстановить сигнал. Тогда суммирование будет идти от n=0 до n=2Fmax*T=2000*0.001=2 // Всего 2 отсчета будет использоваться, а не все 13? //

s(n*dt) - это как раз сами отсчеты которые у меня есть.

Код
// Это массив с отсчетами, которые у меня есть за 1 период

data_01[0]:= 1.10929;
data_01[1]:= 1.02396;
data_01[2]:= 0.85501;
data_01[3]:= 0.54537;
data_01[4]:= 0.31164;
data_01[5]:= 0.08533;
data_01[6]:= 0.02226;
data_01[7]:= 0.09275;
data_01[8]:= 0.26341;
data_01[9]:= 0.56763;
data_01[10]:= 0.81249;
data_01[11]:= 1.0388;
data_01[12]:= 1.09445;

...

//константы, что обговорили выше:
f_max:=1000;
dt:= 0.0005;
x:= 0.0004;

// вычисление значения восстановленного сигнала x(t) в точке x

  for n:=0 to 2 do begin
    buff:= data_01[n]*sin(2*3.14*f_max*(x-n*dt))/(2*3.14*f_max*(x-n*dt));
    result:= result+buff;
  end;


Я получаю 1,0849 - довольно близкий отсчет. Пробую строить сам график, беру 100 точек интерполяции с шагом в 0.0004

Код
for j:=1 to 100 do begin
  result:=0; // обнуляю результат вычисления для каждой новой точки
  dx:= j*0.0004; // шаг восстановления: 0.0004, 0.0008, 0.0016 и.т.д.

  for n:=0 to 2 do begin
    buff:= data_01[n]*sin(2*3.14*f_max*(dx-n*dt))/(2*3.14*f_max*(dx-n*dt));
    result:= result+buff;
  end;

  // И добавляю вычесленную точку на график (x,y)
  Series2.AddXY(dx,result,'',clRed);


В результате получаю вот такую картинку:


синк он мне рисует ... но это не восстановленный сигнал. Как я понял - тут должна быть сумма синков - и тогда образуется нужное.
Или я ошибаюсь? Помогите пожалуйста разобраться, а то голова кругом уже
zi4rox
Всё, вроде разобрался - нужно быть более аккуратным при подборе коэффициентов. Сигнал действительно можно восстановить с любой точностью, для гармонического сигнала - ещё можно и форму подсгладить.


* на рисунку 250 точек на период - это число может быть теоретически любым

Всем спасибо кто помогал!
GeorgyBey
Цитата(zi4rox @ May 24 2009, 12:37) *
Измерять нужно амплитуду. Про цифровую интерполяцию интересно!

Если измерять амплитуду - можно сделать аналоговый дифференциатор, т.е. брать первую производную от вашего синуса, получится косинус.
Моменты перехода косинуса через 0 будут соответствовать амплитуде синуса. Компаратор контроллера ловит переход косинуса из 0(минус обрезан, понятное дело) в + и запускает замер АЦП. При спаде из + в 0 можно замерять нижнюю амплитуду.
Может в перерывах успеет в комп согнать ин-фу?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.