|
|
  |
Практическое использование схемы/блока захвата в 16ти разрядных таймерах AVR Mega |
|
|
|
May 27 2009, 07:13
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Давайте попробуем. Сначала немного теории на пальцах. Если бы мы точно знали фазу начального сигнала, то интеграл ) , где A - входной сигнал,  - круговая частота,  - фаза сигнала, был бы равен значению амплитуды полосы спектра во входном сигнале с центральной частотой  и полосой, равной  , где t - время интегрирования. Но мы не знаем фазу сигнала. Поэтому делается два интегратора ) ) Второй отличается от первого сдвигом фазы опорного сигнала на 90 градусов. Если быть точным, то I и Q представляют из себя действительные и мнимые значения результата дискретного преобразования Фурье для выбранной полосы спектра. Для того, чтобы получить реальную амплитуду необходимо вычислить длинну вектора с координатами I и Q  Для наших целей корень вполне можно опустить. Итого, для определения двух частот необходимо вычислить четыре интеграла ) ) ) ) А затем, после интегрирования, получить значения мощностей   Далее, банально сравниваем Код if ((A50>THRESH)||(A51>THRESH)) { if (A50>A51) { //Есть сигнал с частотой 50кГц } else { //Есть сигнал с частотой 50кГц } } else { //Сигнала нет } где THRESH - порог обнаружения. Теперь, от математики надо перейти к реальной жизни. Во-первых, определиться с параметрами. Т.к. полоса обнаружения определяется временем интегрирования, то хорошим выбором будет 1мс. Это эквивалентно полосе в 1кГц. Для простоты реализации на восьмибитных процессорах имеет смысл выбрать частоту дискретизации, ну например, 256кГц (это примерно 5 отсчетов на период сигнала). Далее, вместо полноценного АЦП будем использовать компаратор. Его можно рассматривать как однобитный АЦП. Так как сигнал имеет разрядность один бит, то разрядность опорного сигнала тоже нужно брать 1 бит (больше просто нет смысла). Причем, этот бит определяет просто знак. Т.е. если бит равен 0 - значение сигнала равно -1, если бит равен 1 - значение сигнала равно +1. Теперь нарисуем таблицу умножения в наших терминах Код a,b,a*b: -1,-1,+1 +1,-1,-1 -1,+1,-1 +1,+1,+1 и заменим значения уровня сигнала (+1/-1) на битовые значения(1/0) Код a,b,a*b: 0,0,1 1,0,0 0,1,0 1,1,1 Если мы внимательно посмотрим на таблицу, то увидим, что a*b=not (a xor  . Т.к. входной сигнал мы можем безболезненно проинвертировать, то not можно убрать. Значит, все умножение входного сигнала на опорный сводится к выполнению операции xor между значениями. Следовательно, каждый интегратор в коде будет представлять из себя Код I+=signal^reference; , где I - интегратор, signal - выборка сигнала, reference - табличное значение опорного сигнала. Тут надо обратить внимание на то, что после интегрирования необходимо вычесть из интегратора половину от количества выборок. Происходит это по простой причине - мы вместо прибавления +1 и -1 к интегратору прибавляем либо 1, либо 0, что дает сдвиг на полдиапазона. Либо можно начальное значение интегратора задавать не 0, а минус половина количества выборок. Теперь про оптимизацию. Если делать интегрирование на каждой выборке - это будет большой перерасход ресурсов. Посему, надо обрабатывать сразу 8 бит. Для начала - о получении 8ми бит. Надо просто выход компаратора подключить, например, ко входу MOSI, а на вход SCK подать нужную частоту выборок. В результате, в каждом байте, читаемом из SPDR будет получено 8 выборок подряд. Теперь о обработке. Код I+=bitcount_table[byte_signal^byte_reference] , где byte_signal - 8 выборок сигнала в виде одного байта, byte_reference - 8 выборок опорного сигнала в виде одного байта, bitcount_table - таблица длинной 256 байт, каждый байт которой равен количеству единичных бит в индексе. Теперь попробуем написать код интегратора более близкий к реальности. При этом для простоты разместим 2 таблицы непосредственно в конце флеша, причем, таблица опорных сигналов будет представлять из себя записи по 4 байта, каждый байт - восемь выборок для сигналов I50,Q50,I51,Q51 соответственно, общей длинной ((256 выборок всего)/(8 выборок в байте))*(4 сигнала)=128 байт Код typedef unsigned char UREG; typedef signed char REG; typedef signed char INT8; typedef unsigned char UINT8;
volatile UINT8 I50; volatile UINT8 Q50; volatile UINT8 I51; volatile UINT8 Q51;
__flash UINT8 bitcount_table[256] @ FLASHEND-0xFF; __root __flash UINT8 reference_sig[128] @ FLASHEND-0xFF-0x80;
volatile UINT8 Int_Idx; //Начальное значение - 0x80
__interrupt void ProcessIntegrators(void) { UINT8 __flash *r=(UINT8 __flash *)(FLASHEND-0xFF-0x100)+Int_Idx; //Текущее положение в таблице опорных сигналов UREG sig_i50; UREG sig_q50; UREG sig_i51; UREG sig_q51; sig_i50=sig_q50=sig_i51=sig_q51=SPDR; sig_i50^=*r++; //Операция умножения входного сигнала на опорные sig_q50^=*r++; sig_i51^=*r++; sig_q51^=*r++; Int_Idx=(int)r; //Сохранение указателя I50+=bitcount_table[sig_i50]; //Собственно интегрирование Q50+=bitcount_table[sig_q50]; I51+=bitcount_table[sig_i51]; Q51+=bitcount_table[sig_q51]; } Некоторое колдовство имеется с указателем Int_Idx. Для уменьшения оверхеда его начальное значение должно быть 128, и когда он досчитает до 0, то результат интегрирования будет готов. Вот результат компиляции EWAVR 5.11 CODE RSEG NEAR_Z:DATA:NOROOT(0) REQUIRE `?<Segment init: NEAR_Z>` I50: DS 1 Q50: DS 1 I51: DS 1 Q51: DS 1 // 11 // 12 volatile UINT8 Int_Idx; //Начальное значение - 0x80 Int_Idx: DS 1 // 13
RSEG CODE:CODE:NOROOT(1) // 14 __interrupt void ProcessIntegrators(void) ProcessIntegrators: // 15 { ST -Y, R31 ST -Y, R30 ST -Y, R22 ST -Y, R21 ST -Y, R20 ST -Y, R19 ST -Y, R18 ST -Y, R17 ST -Y, R16 IN R21, 0x3F // 16 UINT8 __flash *r=(UINT8 __flash *)(FLASHEND-0xFF-0x100)+Int_Idx; //Текущее положение в таблице опорных сигналов LDS R16, (I50 + 4) LDI R31, 62 MOV R30, R16 // 17 UREG sig_i50; // 18 UREG sig_q50; // 19 UREG sig_i51; // 20 UREG sig_q51; // 21 sig_i50=sig_q50=sig_i51=sig_q51=SPDR; IN R17, 0x2E MOV R16, R17 MOV R18, R17 MOV R20, R17 MOV R22, R17 // 22 sig_i50^=*r++; //Операция умножения входного сигнала на опорные LPM R17, Z+ EOR R22, R17 // 23 sig_q50^=*r++; LPM R17, Z+ EOR R20, R17 // 24 sig_i51^=*r++; LPM R17, Z+ EOR R18, R17 // 25 sig_q51^=*r++; LPM R17, Z+ EOR R16, R17 // 26 Int_Idx=(int)r; //Сохранение указателя STS (I50 + 4), R30 // 27 I50+=bitcount_table[sig_i50]; //Собственно интегрирование MOV R30, R22 LDI R31, 63 LPM R17, Z LDI R30, LOW(I50) LDI R31, (I50) >> 8 LD R19, Z ADD R19, R17 ST Z, R19 // 28 Q50+=bitcount_table[sig_q50]; MOV R30, R20 LDI R31, 63 LPM R17, Z LDI R30, LOW(I50) LDI R31, (I50) >> 8 LDD R19, Z+1 ADD R19, R17 STD Z+1, R19 // 29 I51+=bitcount_table[sig_i51]; MOV R30, R18 LDI R31, 63 LPM R17, Z LDI R30, LOW(I50) LDI R31, (I50) >> 8 LDD R18, Z+2 ADD R18, R17 STD Z+2, R18 // 30 Q51+=bitcount_table[sig_q51]; MOV R30, R16 LDI R31, 63 LPM R16, Z LDI R30, LOW(I50) LDI R31, (I50) >> 8 LDD R17, Z+3 ADD R17, R16 STD Z+3, R17 // 31 } OUT 0x3F, R21 LD R16, Y+ LD R17, Y+ LD R18, Y+ LD R19, Y+ LD R20, Y+ LD R21, Y+ LD R22, Y+ LD R30, Y+ LD R31, Y+ RETI
Ну и финальное действие по достижению переменной Int_Idx значения 0 - оно банально: Код #define THRESH (20*0x100)
UREG TestIntegrators(void) { __disable_interrupt(); REG i50=I50; REG q50=Q50; REG i51=I51; REG q51=Q51; __enable_interrupt(); unsigned int A50=__multiply_signed(i50,i50)+__multiply_signed(q50,q50); unsigned int A51=__multiply_signed(i51,i51)+__multiply_signed(q51,q51); if ((A50>THRESH)||(A51>THRESH)) { if (A50>A51) return 1; else return 2; } return 0; } В качестве упражнения рекомендую сгенерировать самому необходимые таблицы, написать необходимую инициализацию измерения и проверку окончания. А теперь - ваши вопросы
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 27 2009, 13:32
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Буратино @ May 26 2009, 17:58)  Но для общего развития намекните приблизительно, как эТО делают при помощи корреляционного метода ? корреляционный метод ловли частоты это конечно здорово, и Rst7 все грамотно описал, тока мне почему-то кажеться что Вам это нафиг не нужно...(да и периодов нужно довольно много) При наличии помех стабильно выделить наборы частот будет сложно(за короткий интервал без помех), а вот определить что частота стала < определенной очень легко, может в этом направлении подумать в смысле схемотехники ? Т.е. срабатывание сигнализации == (частота < определенной), тогда прога будет совсем простой а любые помехи просто чуть мешают "скорости" определения срабатывания сигнализации...
Причина редактирования: Излишнее цитирование.
|
|
|
|
|
May 27 2009, 13:50
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Если эта тема коррелирует с той, в которой топикстартер делает приемник прямого усиления, то корреляционный прием в течении 1мс - как раз. У него добротность входного контура выходит порядка 50  Да, кстати. Небольшое улучшение кода коррелятора Код volatile struct { UINT8 I50; UINT8 Q50; UINT8 I51; UINT8 Q51; };
__flash UINT8 bitcount_table[256] @ FLASHEND-0xFF; __root __flash UINT8 reference_sig[128] @ FLASHEND-0xFF-0x80;
volatile UINT8 Int_Idx; //Начальное значение - 0x80
__interrupt void ProcessIntegrators(void) { UINT8 __flash *r=(UINT8 __flash *)(FLASHEND-0xFF-0x100)+Int_Idx; //Текущее положение в таблице опорных сигналов UREG sig_i50; UREG sig_q50; UREG sig_i51; UREG sig_q51; sig_i50=sig_q50=sig_i51=sig_q51=SPDR; sig_i50^=*r++; //Операция умножения входного сигнала на опорные sig_q50^=*r++; sig_i51^=*r++; sig_q51^=*r++; Int_Idx=(int)r; //Сохранение указателя sig_i50=bitcount_table[sig_i50]; //Подсчет единичных бит sig_q50=bitcount_table[sig_q50]; sig_i51=bitcount_table[sig_i51]; sig_q51=bitcount_table[sig_q51]; I50+=sig_i50; //Собственно интегрирование Q50+=sig_q50; I51+=sig_i51; Q51+=sig_q51; } И результат CODE RSEG CODE:CODE:NOROOT(1) // 15 __interrupt void ProcessIntegrators(void) ProcessIntegrators: // 16 { ST -Y, R31 ST -Y, R30 ST -Y, R22 ST -Y, R21 ST -Y, R20 ST -Y, R19 ST -Y, R18 ST -Y, R17 ST -Y, R16 IN R21, 0x3F // 17 UINT8 __flash *r=(UINT8 __flash *)(FLASHEND-0xFF-0x100)+Int_Idx; //Текущее положение в таблице опорных сигналов LDS R16, (_A_I50 + 4) LDI R31, 62 MOV R30, R16 // 18 UREG sig_i50; // 19 UREG sig_q50; // 20 UREG sig_i51; // 21 UREG sig_q51; // 22 sig_i50=sig_q50=sig_i51=sig_q51=SPDR; IN R17, 0x2E MOV R16, R17 MOV R18, R17 MOV R20, R17 MOV R22, R17 // 23 sig_i50^=*r++; //Операция умножения входного сигнала на опорные LPM R17, Z+ EOR R22, R17 // 24 sig_q50^=*r++; LPM R17, Z+ EOR R20, R17 // 25 sig_i51^=*r++; LPM R17, Z+ EOR R18, R17 // 26 sig_q51^=*r++; LPM R17, Z+ EOR R16, R17 // 27 Int_Idx=(int)r; //Сохранение указателя STS (_A_I50 + 4), R30 // 28 sig_i50=bitcount_table[sig_i50]; //Подсчет единичных бит // 29 sig_q50=bitcount_table[sig_q50]; MOV R30, R20 LDI R31, 63 LPM R20, Z // 30 sig_i51=bitcount_table[sig_i51]; MOV R30, R18 LPM R18, Z // 31 sig_q51=bitcount_table[sig_q51]; MOV R30, R16 LPM R16, Z // 32 I50+=sig_i50; //Собственно интегрирование MOV R30, R22 LPM R17, Z LDI R30, LOW(_A_I50) LDI R31, (_A_I50) >> 8 LD R19, Z ADD R19, R17 ST Z, R19 // 33 Q50+=sig_q50; LDD R17, Z+1 ADD R17, R20 STD Z+1, R17 // 34 I51+=sig_i51; LDD R17, Z+2 ADD R17, R18 STD Z+2, R17 // 35 Q51+=sig_q51; LDD R17, Z+3 ADD R17, R16 STD Z+3, R17 // 36 } OUT 0x3F, R21 LD R16, Y+ LD R17, Y+ LD R18, Y+ LD R19, Y+ LD R20, Y+ LD R21, Y+ LD R22, Y+ LD R30, Y+ LD R31, Y+ RETI
Так быстрее немного
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 27 2009, 14:13
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Rst7 @ May 27 2009, 18:02)  Что мне представлять, за меня большие головы давно подумали, и определили, что описанный корреляцинный способ приема - оптимальный. А остальное - от лукавого. Не ожидал от Вас услышать такое... Несомненно корреляцинный способ приема оптимальный - при определенных обстоятельствах... Тока вот обстоятельства не факт что соответствуют  выбранному методу... (или наоборот...) Автор топика сказал что у него помехи могут быть в любой момент, поэтому ИМХО, будет работать только способ определения минимальной частоты...
|
|
|
|
|
May 27 2009, 15:47
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата Не ожидал от Вас услышать такое... Да ладно, это мне мои телепатические способности подсказывают  Шучу. Вносите Ваше предложение о способе обнаружения сигналов, будем считать, где порог по с/ш лучше. Хотя, лучше подождем, пока нам топикстартер расскажет о параметрах его сигнала. Иначе мы тут без исходных данных холивар как разведем - только поругаемся...
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 27 2009, 18:36
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Rst7 @ May 27 2009, 19:47)  Да ладно, это мне мои телепатические способности подсказывают  Шучу. Вносите Ваше предложение о способе обнаружения сигналов, будем считать, где порог по с/ш лучше. дык все очень просто, прерывание EXTINT(или компаратор) на ноге и прерывание от таймера которое запускается в прерывании от ножки... прерывание от таймера настраиваем в прерываниии EXTIN(причем так чтоб прерывание возникло только если T > T реальное) Таким образом окажемся в прерывании таймера толко если F(частота) > заданой В принципе, есть возможность привязаться таймером к моменту перехода, тч джитера может не быть совсем... Цитата Хотя, лучше подождем, пока нам топикстартер расскажет о параметрах его сигнала. Иначе мы тут без исходных данных холивар как разведем - только поругаемся... не..., ругацо не нада...
|
|
|
|
|
May 27 2009, 19:46
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Цитата(Rst7 @ May 27 2009, 21:47)  Хотя, лучше подождем, пока нам топикстартер расскажет о параметрах его сигнала. Иначе мы тут без исходных данных холивар как разведем - только поругаемся... Кстати, если топикстартер расскажет нам что полоса сигнала ограничена (или её можно ограничить неким полосовым фильтром) то частоту сэмплирования можно и понизить, вплоть до нескольких килогерц (undersampling). При этом, конечно, уменьшится и число отсчётов за миллисекунду и увеличится погрешность в вычисленных I и Q, ну да это вопрос выбора между сложностью и точностью.
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|