Результаты Arduino FFT "красивого" сигнала кажутся противоречивыми
У меня есть ПРЕКРАСНЫЙ доплеровский радиолокационный сигнал от датчика 24.050-24.250 ГГц, измеряющего очень маленький объект со скоростью 143 кадра в секунду (скорость от другого радара 10 ГГц) в области измерения около 300 мм-500 мм перед датчиком(датчиками). Сигнал был ограничен примерно 3 В с помощью стабилитрона.
Я сделал несколько измерений (при такой скорости, размере объекта и расстоянии от датчиков), и в среднем было около 8-20 волновых пиков выше порогового уровня триггера (2,58 В) до конца коробки порогового уровня триггера, где пики начинают падать.
Глядя на график, можно отбросить первые 3 пика и последние 2-3 пика выше порога триггера, что оставляет приличную область (оранжевый прямоугольник) для выборки пиков по частоте/периоду. Таким образом, в этом случае у нас есть около 17 "хороших" пиков внутри оранжевого ящика, которые нужно измерить. В этом случае оранжевая коробка (измерительная площадь образца) имеет длину 5 х 500 us = 2500 us.
Я знаю, что БПФ был бы лучшим способом измерения, но одна программа БПФ, которую я использовал с Arduino, дала мне противоречивые результаты. Не уверен, как установить размер выборки (должен быть в силе 2 приращения от 2 до 256). А максимальная частота дискретизации составляет 10 кГц (аппаратные ограничения).
Я установил размеры выборки на 4, 16 и 128 на частоте 10 кГц, но получил противоречивые результаты. Я подозреваю логарифмические результаты, но даже они не складываются. Иногда я получаю в пределах 2-3%, но иногда это отклоняется на 30% без видимой корреляции.
Что я знаю:
- с помощью этого радара с частотой 24 ГГц (без углов) скорость = частота / 44 достигает км/ч (км/ч х 1,097 = кадров в секунду).
- в этом случае o-scope измерял 6613 Гц с периодом 151,2 us, но это было для всей области выше порога срабатывания 2,58 В. Но у него также были некоторые гораздо более изменчивые показания, такие как заметные в первые 2-3 пика после триггера и последние 2-3 пика, которые падают ниже порога триггера. Я исключил их из оранжевой коробки.
Как мне настроить этот БПФ, или другой БПФ, или аналогичный метод, который определял бы доминирующую частоту по данным внутри оранжевого прямоугольника? Размер выборки оранжевого прямоугольника всегда будет находиться в диапазоне от 8 до 20 пиков числа пиков. Я измерил частоту и периоды от "положительного восходящего фронта до положительного восходящего фронта".
Я попробовал использовать Adafruit nRF52840 Express (часы 16 Мгц) и Adafruit 32u4 Bluefruit (часы 8 Мгц).
Я использую эту библиотеку Arduino FFT: https://github.com/kosme/arduinoFFT
Некоторая широкая информация о самом этом БПФ: https://www.norwegiancreations.com/2017/08/what-is-fft-and-how-can-you-implement-it-on-an-arduino/
- Спасибо.
#include "arduinoFFT.h"
#define SAMPLES 4 //Must be a power of 2 128, 256?
#define SAMPLING_FREQUENCY 10000 //Hz, must be less than 10000 due to ADC
arduinoFFT FFT = arduinoFFT();
unsigned int sampling_period_us;
unsigned long microseconds;
double vReal[SAMPLES];
double vImag[SAMPLES];
void setup() {
Serial.begin(115200);
sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
}
void loop() {
if (analogRead(A0) >600) {
/*SAMPLING*/
for(int i=0; i<SAMPLES; i++)
{
microseconds = micros(); //Overflows after around 70 minutes!
vReal[i] = analogRead(A0);
vImag[i] = 0;
while(micros() < (microseconds + sampling_period_us)){
}
}
/*FFT*/
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
/*PRINT RESULTS*/
Serial.println(peak); //Print out what frequency is the most dominant.
// for(int i=0; i<(SAMPLES/2); i++)
// {
/*View all these three lines in serial terminal to see which frequencies has which amplitudes*/
//Serial.print((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
//Serial.print(" ");
// Serial.println(vReal[i], 1); //View only this line in serial plotter to visualize the bins
// }
}
//delay(1000); //Repeat the process every second OR:
// while(1); //Run code once
}
ПРАВКА: @Dorian После нескольких дней невзгод и разочарований, я читал и перечитывал вашу дополнительную информацию и помог мне лучше прояснить ситуацию. Я думаю, что у меня есть некоторые аппаратные ограничения. Кстати...да, у меня есть конденсатор 27pf на GND с резистором 3,3 K и 3V zener параллельно на выходе OP AMP.
Но сначала поясню: я решил добавить компаратор после датчика и операционного усилителя. Теперь у меня есть базовое напряжение на ВЫСОКОМ уровне (3,1 В). Ранее, как я уже писал, OP AMP имел базовый уровень 1,65 В, и при обнаружении движения напряжение отскакивает между максимумами (2,5 В-3,1 В) и минимумами (1 В-0 В) примерно в 10-20 раз, пока оно снова не установится на базовом уровне 1,65 В. Я подозревал, что ВЫСОКИЙ и НИЗКИЙ пороги были не так уж ясны. Чтобы получить четкий МАКСИМУМ или МИНИМУМ, я добавил компаратор. Эти показания идут на цифровой вывод захвата MCU, способный к тикам 62,5 нс (16 МГц). Программа Arduino, которая подсчитывает импульсы, проверяется на работу. В спецификациях MCU при 3,3 В имеет 1 В и ниже как НИЗКИЙ, так и 2,5 В и выше как ВЫСОКИЙ.
См. Новое чтение oscope (прилагается). Я получаю точные импульсные захваты (соответствующие oscope), но я получаю только около 3 или 4 импульсных показаний вместо 10-20, показанных на прицеле. Я использовал НИЗКИЙ захват (ниже 1В). Но даже если я переключусь на TOGGLE capture (double) Кажется, я получаю только последние 3-4 полных волны (1/3) и, похоже, пропускаю первые 2/3. Или может получаться каждый 2-й или 3-й?
Мой операционный усилитель работает быстро на частоте 50 МГц, и раньше я точно измерял с его помощью импульсы 100ус-800ус. А мой компаратор (после операционного усилителя) - это MAX 9052 с задержкой распространения 400 нс. время подъема/падения 40-80 нс. Так что я не должен пропустить ни одного импульса. Программа Arduino тоже не может быть такой медленной.
ПРАВКА №2:
//the best resolution you can achieve is 1/16us.
#include <Arduino.h>
#define FREQ_MEASURE_PIN 8 // actual 6 is PIN D11 and 8 is PIN D12 on Adafruit Feather Express nRF52840 LE, pin 11 is D12 itsybitsy 52840
#define PPI_CHANNEL 1u
#define GPIOTE_CHANNEL 1 //just picked channel #1
volatile int pulseCount = 0;
volatile unsigned long duration; //Pulse2 - Pulse1 = count of time ticks at 62.5 ns each tick (16 Mhz clock scaled at 0) (expected value example: 792.5620 => 7925620)
volatile unsigned long pulseTime; // first signal reading
volatile unsigned long lastTime; // most current signal reading
void setup() {
Serial.begin(115200);
initCounter();
}
void loop()
{
if ((pulseCount == 2) && (duration>0)) {
Serial.println(duration); //
}
}
//must use extern "C" because IRQ will not compile since it's "C" coded
extern "C"
{
void GPIOTE_IRQHandler(void)
{
lastTime = pulseTime;
if (NRF_GPIOTE->EVENTS_IN[GPIOTE_CHANNEL] == 1) //if an input pulse is detected on pin 6 then...
{
NRF_GPIOTE->EVENTS_IN[GPIOTE_CHANNEL] = 0; // reset event detection to zero to ready for next event detection?
pulseTime = NRF_TIMER2->CC[0]; // save Timer value at same time when signal was read on pin 6
//pulseCounter
pulseCount++;
duration =(((pulseTime*10000) - (lastTime*10000))/16); //multiply by 10000 to avoid float, and divide by 16 for 16 Mhz clock tick = 62.5 ns per tick
// goes from here to Loop if pulse = 2 (complete PULSE) so a reading can be sent
}
}
}
void initCounter()
{
NRF_P0->PIN_CNF[FREQ_MEASURE_PIN] = GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos | //sets up PIN 6 for event read
GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos | //pos going signal
// GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos | //pulldown LOW so no floating of pin voltage
// GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos; //a HIGH POS signal is the trigger
GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos | //Pullup or Pulldown LOW so no floating of pin voltage
GPIO_PIN_CNF_SENSE_Low << GPIO_PIN_CNF_SENSE_Pos; //a HIGH POS signal is the trigger .... or a LOW POS
NRF_PPI->CHEN |= 1 << PPI_CHANNEL;
NRF_PPI->CH[PPI_CHANNEL].EEP = (uint32_t)&NRF_GPIOTE->EVENTS_IN[GPIOTE_CHANNEL];
NRF_PPI->CH[PPI_CHANNEL].TEP = (uint32_t)&NRF_TIMER2->TASKS_CAPTURE[0]; //sets up Timer channel
NRF_GPIOTE->CONFIG[GPIOTE_CHANNEL] = GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos | //sets up pin for event capture
FREQ_MEASURE_PIN << GPIOTE_CONFIG_PSEL_Pos | //sets up event capture on pin 6
GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos; //sets event capture signal trigger type: LoToHi or HiToLo or Toggle
NRF_GPIOTE->INTENSET = (1 << GPIOTE_CHANNEL); // Interrupt routine setup on a pin
NVIC_EnableIRQ(GPIOTE_IRQn); // Interrupt routine setup if signal detected on pin 6
NRF_TIMER2->TASKS_STOP = 1; //stops timer
NRF_TIMER2->TASKS_CLEAR = 1; //clear timer to zero
NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos; //sets up TIMEr mode as "Timer"
NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos; // sets values for Timer input
NRF_TIMER2->PRESCALER = 0; //read at max resolution (at MCU speed)
NRF_TIMER2->TASKS_START = 1; // starts the Timer
}
ПРАВКА #3: ================================================
Я добавил схему операционного усилителя ниже. Эта схема прекрасно работала с индуктивным датчиком, использующим вихревые токи. Я очень точно измерил одиночные импульсы @ 700-800us, но у меня не было резистора R1 (22k). Добавил резистор R1 и GND сразу после него, когда заменил индуктивный датчик на радарный датчик 24 ГГц, потому что я не получал показаний. Эта схема обеспечивает первый график, который я опубликовал, с центром около 1,6 В. Я снял компаратор после выключения операционного усилителя, чтобы не усложнять схему, а также у него были некоторые артефакты.
Подводя итог: есть подозрение, что программа Arduino, которую я разместил для nRF52, недостаточно быстра, чтобы захватить 100us импульсов в быстрой последовательности. Я пытался использовать только BLE и раскомментировал SerialPrint и SerialBegin и т. Д., но даже с BLE я получил те же ограниченные показания импульса. Например: было 10-20 импульсов, я смог захватить только последнюю 1/3 импульсов (3-4). Я также попробовал HIGH и LOW (HiToLo/LoToHi/Toggle).
Радарный датчик-это: источник питания 3,3 В. ЕСЛИ выход (считывание сигнала) находится в диапазоне 60мВ-250мВ. 60 мв - это состояние нулевого сигнала.
Here are some sample period (wave pulse) readings in micro seconds:
97.0000
53.2500
45.2500
42.0625
40.8125
**40.9375**
And the actual period that it should read based on reference measurement: **38.4435**us
==========================
Another set of period (wave pulse) readings in micro seconds:
95.6875
55.0000
46.7500
41.7500
**40.2500**
And the actual period that it should read based on reference measurement: **39.1703**us
Таким образом, последнее значение довольно близко, но не пропорционально близко, где я могу надежно "оценить" фактическое значение. Так что, например, каждый раз он снижается не на 5,13%, а на 3-6%.
График примера волновых импульсов (меньший означает более короткий импульс):
Стабилитрон на выходе предназначен для того, чтобы удерживать волны от превышения 3,3 В, что может повредить входной захватный штифт микроконтроллера.
Спасибо вам за вашу помощь!
Только для информации: ЭТО БЫЛИ ПОКАЗАНИЯ ОСЦИЛЛОГРАФА СО СХЕМОЙ КОМПАРАТОРА, ДОБАВЛЕННОЙ К ВЫХОДУ ОПЕРАЦИОННОГО УСИЛИТЕЛЯ, НО С ТЕХ ПОР Я УДАЛИЛ СХЕМУ КОМПАРАТОРА:
EDIT: Это была довольно большая задержка, так как мне нужно было сделать что-то еще после того, как я ничего не добился с этим проектом. Затем сегодня, когда я снова боролся, я думаю, что пришел к решению. Это требует больше работы, но, по крайней мере, у меня есть собранная версия, которая, кажется, хорошо работает.
Проблема, по-видимому, заключалась в том, что сам сигнал был синусоидальной или квазиквадратичной волной. Используя скетч Arduino AVR для внутреннего компаратора, которому ISR компаратора помогает "квадратировать" входящий сигнал с помощью таймеров и прерываний, переключая другой вывод на вывод Ref компаратора, я смог получить надежные показания. Я фактически использовал внешний компаратор с AVR и nRF52 для подсчета периодов. Это программа и смотрит другой человек тоже прошел через ад: https://electronics.stackexchange.com/questions/357131/random-and-unpredictable-analog-comparator-behaviour/566974#566974
Я предпочитаю использовать nRF52 из-за интеграции BLE, но я думаю, что смогу заставить AVR работать сначала автономно, выяснив, как отредактировать библиотеку, чтобы обратить прерывание с низкого уровня на Высокий, с высокого на низкий...так как выход компаратора противоположен моему сигнальному входу.
Конечно, мне все еще нужно обработать показания, чтобы отсортировать доминирующую частоту, но вручную я смог вычислить 5 из 5 событий в пределах 2-5% от действительного значения.
Однако, по-видимому, ключом к надежному считыванию входного сигнала является дополнительный вывод, который используется для "преобразования" синусоидальной волны в квадрат в рамках процедуры прерывания компаратора.
Мне все еще нужно обернуть голову вокруг того, как дополнительный вывод программы AVR, переключенный LOW/HIGH, подключенный к VREF компаратора, "формирует" синусоидальную волну и действует как обратная связь для гистерезиса. Я верю, что какой бы способ я ни пришел к "хорошей" прямоугольной волне для считывания входного счетчика AVR или nRF52, он будет победителем. Но я открою новую тему, если застряну. Спасибо вам за вашу помощь, и любые ваши предложения приветствуются.
@TommyS, 👍0
Обсуждение2 ответа
Чтобы получить значимый результат от преобразования Фурье, входной сигнал должен быть отфильтрован до полосы пропускания не более половины частоты дискретизации.
Ваша максимальная частота дискретизации 10 кГц , которая, как я полагаю, задается максимальной частотой дискретизации АЦП, меньше чем вдвое превышает 6,61 кГц, базовую частоту вашего сигнала.
Более того, вы ограничиваете сигнал, добавляя высокочастотные компоненты к сигналу, который уже не вписывается в требуемую полосу пропускания.
Вам лучше придерживаться нулевого перекрестного обнаружения, используя как восходящие, так и падающие края, чтобы иметь больше данных для усреднения.
Вы также можете проверить, какая часть сигнала имеет правильные данные о скорости относительно реальной скорости или проверить паттерн, я вижу, что средний период ниже, чем в начале и конце сигнала.
Более поздняя правка. Некоторые вещи вы должны проверить и объяснить, почему бессмысленно использовать БПФ для этого.
Во-первых, я вижу, что у вас чистый средний центрированный сигнал между -0,7 и 3В. Возможно, на датчике есть выходной конденсатор, который автоматически ограничивает себя между напряжением стабилитрона и нижним зажимным диодом. Середина находится где - то на уровне 1,5 В. Но середина логического напряжения находится где-то на половине VDD, 2,5 В.
Может быть, именно поэтому у вас есть вариации длины импульса от начала до конца импульса поезда, потому что линия принятия решения находится выше средней линии.
Конечно, установка решения вокруг средней линии может дать много шума, но вы можете использовать либо детектор огибающей, чтобы увидеть, когда начинается импульс, либо триггер Шмидта, так что пройдет только сигнал выше гистерезиса.
Я думаю, что действительно обнаружение проходов вокруг средней точки даст вам более надежные и последовательные результаты.
Что касается использования дискретного преобразования Фурье (быстрого или нет) для нахождения базовой частоты сигнала, то нет никакого способа получить разумное разрешение, используя такой короткий сигнал.
ДПФ дискретен не только по времени, но и по частоте. Любой, кто имеет базовые знания о DFT знает, что максимальное разрешение на частоты, которые вы можете получить в Т таймфрейм 1/т, на 2,5 мс частота будет ступенчато 400Гц, если у вас есть максимум 8 кГц сигнал, вы будете иметь 20 фиксированных значений частоты от 0 до 8 кГц независимо от того, сколько образцов вы принимаете, независимо от того, на какой программы можно производить обработку или платформы. Это тупик.
Спасибо @ Dorian. Вчера я провел несколько часов на Arduino и с опорным доплеровским радаром (для реальной скорости), пытаясь извлечь шаблоны данных, которые повторяются и соответствуют реальной скорости, по крайней мере, удаленно. Мои условия испытаний идеальны, но получают значительные отклонения, которых не должно быть. Мне нужно еще раз посетить теорию/etc за допплером, а также прочитать об обработке сигналов. Мне нужно посмотреть на 30 000 футов, потому что я думаю, что бегу по кроличьим норам., @TommyS
@ Дориан, пожалуйста, ознакомьтесь с моими правками выше в оригинальном посте. Я добавил компаратор, чтобы получить четкий МИНИМУМ вместо пересечения нуля. Когда я разбираю показания своего телескопа и вручную исследую каждую волну, они совпадают с импульсами, полученными микроконтроллером. Но, похоже, не хватает первых 2/3 и последней волны или двух., @TommyS
Выше говорилось, что мне нужно настроить с нуля макет ob op и также пересмотреть мой компаратор, потому что текущий усилитель OP находится на припаянной печатной плате и может сделать так много только для "перестановки" двух входов. Буду отчитываться. Убедитесь, что операционный усилитель и компараторы работают достаточно быстро для сигнала с периодом 50 С (минимум двойной частоты)., @TommyS
Я понимаю, что распаять R27 сложно. Вы также можете использовать меньший R23, чтобы уменьшить коэффициент усиления за счет подключения параллельного резистора., @Dorian
К сожалению, у меня большая часть операционного усилителя погребена в горячем клею. Я создаю новый и тщательно выбираю пропускную способность и т. Д. Также микросхема компаратора для получения четких максимумов/минимумов. Должен получить его в эти выходные. Иногда это расстраивает (потому что у меня огромные пробелы в знаниях), но маленькие победы компенсируют это! :), @TommyS
*Есть ли причина для трусливого молчаливого понижения голоса?* - Смотрите [Почему предоставление обратной связи не является обязательным для понижения голоса и почему идеи, предполагающие такое негативное восприятие?](https://meta.stackexchange.com/questions/325416/why-isnt-providing-feedback-mandatory-on-downvotes-and-why-are-ideas-suggestin). Комментарии **не требуются** при понижении, и отсутствие комментария не является трусостью. Прочтите ссылку, чтобы понять, почему. Если вам пришлось комментировать понижающие голоса, то, конечно, повышающие голоса без комментариев тоже трусливы? Пусть это тебя не беспокоит. Я получаю отрицательные отзывы на свои посты и просто игнорирую их. :), @Nick Gammon
@NickGammon Спасибо, Ник, Я объяснил, почему я понизил голос другого ответа, чтобы другие оценили его сами по себе, и в обмен вскоре после того, как я получил молчаливое голосование против, я могу только догадываться, что это было от парня, за которого я проголосовал. Почему я должен объяснять, почему я должен отвечать на хороший и полный ответ? Вы могли бы сделать что-то, по крайней мере, там, где у даунвотера есть свой собственный ответ., @Dorian
@Дориан, делающий предположения о том, кто опустил голос и/или почему, приведет к разочарованию-не идите по этому пути. Неясно, что было бы разумно делать, если бы нисходящий-с-ответом нисходил с другим ответом: случайное присвоение нисходящей мотивации со стороны широкой общественности достаточно чревато-для этого было бы еще хуже использовать какой-либо официальный механизм., @Dave Newton
@DaveNewton, вы оба правы. Нет ничего простого. Починка чего-то может сломать что-то другое. Такова жизнь. Спасибо за удаление комментария. Это, конечно, никому не помогло. О, ты не сделал этого, я думал, что это не может быть удалено после всего этого времени. Я сделал., @Dorian
Я не знаю и не могу выяснить, кто голосует за или против. Иногда происходит понижение "мести" - это случается и со мной, и я модератор. (Людям не нравится то, что я сделал, а затем они начинают голосовать против моих постов, лол). *Последовательная* месть-понижение может быть подхвачено автоматизированными системами Stack Exchange. Один или два - это не о чем беспокоиться., @Nick Gammon
Я действительно не могу понять, почему вы не можете поймать импульсы на частоте 6613 Гц. Это не так уж быстро, даже для Уно.
Я провел следующий эксперимент с Uno: я использую таймер 2 для генерации короткой серии импульсов на выводе 11 (PB3 = OC2A). Этот вывод соединен с выводом 8 (ICP1), где я использую таймер 1 для захвата падающих краев. В input capture ISR я подсчитываю количество полученных ребер, а также записываю временные метки первого и последнего ребер. Таким образом, я могу вычислить полученную частоту.
Результатом эксперимента стало то, что таким образом я могу надежно измерять частоты до 125 кГц. Это примерно в 19 раз больше частоты вашего всплеска. Измерение становится ненадежным, если я продолжаю увеличивать частоту.
Вот мой тестовый код:
// Циклы процессора на полупериод импульсного пакета.
const uint16_t half_period = 64;
// Статистика, записанная с помощью входного захвата ISR.
volatile uint16_t capture_count;
volatile uint16_t timer_start;
volatile uint16_t timer_end;
// Input capture ISR.
ISR(TIMER1_CAPT_vect) {
uint16_t now = ICR1;
uint16_t count = capture_count;
if (count == 0)
timer_start = now;
else
timer_end = now;
capture_count = count+1;
}
void setup() {
Serial.begin(9600);
Serial.print("Expected frequency: ");
Serial.print((float) F_CPU / (2*half_period));
Serial.println(" Hz");
Serial.println("Measured frequency:");
Serial.flush();
// Настройте таймер 2 для быстрого ШИМ-сигнала.
DDRB |= _BV(PB3); // цифровой 11 = PB3 = OC2A в качестве выхода
TCCR2A = _BV(COM2A0) // переключить OC2A на сравнение совпадений
| _BV(WGM21); // mode 2 = CTC, TOP = OCR2A
TCCR2B = 0; // держать таймер остановленным
OCR2A = half_period - 1;
// Настройте таймер 1 для захвата входных данных.
TCCR1A = 0; // нормальный режим
TCCR1B = _BV(CS10); // часы @ F_CPU
TIFR1 = _BV(ICF1); // очистить флаг захвата входного сигнала
TIMSK1 = _BV(ICIE1); // включить прерывание захвата входного сигнала
}
void loop() {
// Сбросить счетчик.
capture_count = 0;
// Послать серию импульсов.
TCCR2B = _BV(CS20); // таймер часов 2 @ F_CPU
delayMicroseconds(1000);
TCCR2B = 0; // таймер остановки 2
// Отчет о результатах.
uint16_t timer_cycles = timer_end - timer_start;
uint16_t pulse_count = capture_count - 1;
Serial.print(pulse_count);
Serial.print(" pulses in ");
Serial.print(timer_cycles);
Serial.print(" timer cycles -> ");
Serial.print((float) pulse_count / timer_cycles * F_CPU);
Serial.println(" Hz");
delay(500);
}
И вот результат:
Expected frequency: 125000.00 Hz
Measured frequency:
255 pulses in 32640 timer cycles -> 125000.00 Hz
255 pulses in 32640 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
255 pulses in 32640 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
255 pulses in 32640 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
256 pulses in 32768 timer cycles -> 125000.00 Hz
Большое спасибо @Edgar Bonet за пример программы и предложение. Переключится на AVR (в настоящее время использует nRF52) и протестирует его с помощью вашего метода. Я придерживаюсь рекомендации Дориана о том, чтобы сначала очистить входной сигнал операционного усилителя, который лучше подходит для текущего доплеровского датчика, по сравнению с индуктивным датчиком с одним выстрелом, с которым я использовал его ранее., @TommyS
Я протестировал код и работал так, как вы его опубликовали @Edgar Bonet (за исключением переполнения 65535 в моем случае), но не смог сопоставить показания. Я потратил значительное время на массирование сигнала операционного усилителя, переставив резисторы на обоих входах, но я ограничен предыдущей настройкой печатной платы, которая была для другого типа датчика. Мне нужно настроить новый макет чистого операционного усилителя с нуля, а также пример компаратора, как также предложил Дориан. Буду отчитываться., @TommyS
@TommyS: Переполнение таймера не является проблемой, если пакет помещается в 16 бит, т. е. короче 4,096 мс. Для более длительных пакетов вы можете установить прескалер таймера на 8, что увеличит максимальную продолжительность пакета до 32,768 мс за счет снижения разрешения. В качестве альтернативы вы можете подсчитать переполнения в "TIMER1_OVF_vect", но тогда сложно избежать состояния гонки, когда переполнение срабатывает очень близко к захвату., @Edgar Bonet
Обновленный статус и выявленная наиболее вероятная проблема и обходное решение Откроют новый вопрос о наилучшем пути продвижения вперед в квадратуре синусоиды., @TommyS
- Как определить, когда выходной сигнал датчика значительно меняется?
- создание анализатора гармоник мощности, который будет измерять амплитуды основной и кратных ей частот (например, 50 Гц, 100 Гц, 150 Гц, 200 Гц,...)
- Результаты БПФ, выполненные для аудиосигнала
- Существуют ли библиотеки сглаживания сигналов для Arduino?
- Разные и самые быстрые способы вычисления синусов и косинусов в Arduino
- Подключение HX711 к трехпроводному датчику нагрузки
- Избегайте математических вычислений с плавающей запятой, чтобы ускорить Arduino
- Подключить генератор функций к Arduino
Я бы предположил, что БПФ-это не тот путь, которым вы хотите идти. Поскольку вы заботитесь только о доминирующей частоте, и у вас, по сути, есть прямоугольная волна, вы можете использовать периферийное устройство ввода-захвата, присутствующее в большинстве микроконтроллеров, чтобы измерить время между передними фронтами и вычислить частоту на основе этого., @Majenko
Спасибо. Меня это тоже интересовало. На самом деле у меня есть программа для freq/period с разрешением 62,5 нс. Но я ожидал немного магии БПФ. Тем не менее, я думаю, что вы правы, мне нужно сделать некоторую работу ног и попытаться извлечь доминирующую частоту из этих 8-17 показаний.Я не знаю статистики, но могу почитать. Есть какие-нибудь предложения по поводу того, что применять? Среднее, отклонение и т. Д.? Это примерное чтение периода после того, как я убрал выбросы из начала/конца/нулей/дубликатов: 2703750 2603125 2326250 2391250 2426250 2335625 2090625 2046875 2239375 2145000 2763750 2685625, @TommyS
Я понятия не имею, что означают эти цифры. Если вы измеряете время между последовательными восходящими ребрами и отбрасываете первые результаты X, вы можете взять простое среднее. Это даст вам среднюю скорость по этому набору образцов. Или вы можете взять режим (наиболее распространенный результат) или медиану (среднее значение) или что угодно. Все зависит от того, что вы хотите сделать с данными. Простое среднее среднее, вероятно, самое простое., @Majenko
Спасибо. Эти числа представляют собой значения периодов между последовательными восходящими фронтами. Они должны быть разделены на 10 000 , Чтобы получить 239,125 us , 242,625 us и т. Д. Довольно последовательно После того, как я вынул выбросы "вручную". Будет работать над формулой для автоматизации удаления выбросов., @TommyS
Может быть, средний "режим" сделает это за вас., @Majenko
Читая среднее значение "режима", я думаю, что вы правы, так как это дало бы лучшее представление о "доминирующей" частоте. Попробую это сделать., @TommyS
Использование функции analogRead () в цикле дает минимальный период дискретизации 112 мкс (то есть 8,929 кС/с). При такой частоте дискретизации входной сигнал на частоте 6,613 кГц сглаживается до 2,316 кГц. Но только с 4 образцами спектральное разрешение f_samp/4 = 2,232 кГц., @Edgar Bonet
@Edgar Bonet Спасибо вам за вашу повторную помощь. Первые две программы Arduino, которые я использовал, были цифровым захватом входных контактов регистра AVR Ника Гэммона, смешанным с analogRead() в качестве порога. Но затем, используя аппаратный компаратор, я переключился на nRF52 с переключателем уровня регистра Arduino и низким захватом входных данных на основе прерываний (16 МГЦ) без analogRead(). Осциллограф имеет почти правильные показания частоты/периода, как только я увеличиваю масштаб до выборки из 2-3 волн. С помощью той же программы я могу зафиксировать один импульс около 780 мкс (или даже до 100 мкс.- еще не пробовали), @TommyS
@ Edgar Bonet продолжил: с помощью доплера я получаю импульсы 50-250us как НИЗКИЙ сигнал (полуволна?) Добавлена новая программа Arduino nRF52 выше под EDIT #2., @TommyS
График выглядит довольно плохо. Выложите схему, пожалуйста. Но пропущенные импульсы могут быть вызваны тем, что serial.print() занимает слишком много времени. Это 8 us x 10 бит x не менее двух байт = 160us, что близко к ширине импульса., @Dorian
@Dorian Спасибо за ответ/совет. Я думал о сериальном отпечатке как о возможной проблеме, но отбросил его. Теперь, когда вы упомянули об этом, я переключусь на BLE, который в любом случае будет использоваться финальной программой. Мне нужно пересмотреть схему с добавлением компаратора и резистора на входах операционного усилителя...а затем опубликовать ее. Но позвольте мне сначала попробовать BLE, потому что я подозреваю, что это может быть проблемой. Я изменил SerialPrint с 115200 на 500000 во время пары моих тестов, но не могу вспомнить никакой огромной разницы. Так что БЛЕ первый и доложит! Спасибо., @TommyS
@Dorian Добавил EDIT #3. Реконфигурированная программа Arduino с BLE, но с теми же результатами, только с регистрацией последней 1/3 импульсов. Раскомментированы все "Серийные" строки. Выложил схему OP AMP, но снял дополнение компаратора, чтобы сделать его проще. Обратите внимание, что резистор R1 (22k) и GND после этого являются моими "импровизациями" при переключении с индуктивного датчика (отлично сработал) на текущий радарный датчик 24 ГГц. Эта схема обеспечила "красивый" график (1-й) в моем оригинальном посте. Кроме того, OSCOPE дает правильный freq/период после того, как я фокусируюсь на полной волне около конца серии импульсов., @TommyS
У меня есть простой генератор частоты, и я настрою его на устойчивый импульс 700us для подачи в OP AMP вместо датчика. Постепенно начнет уменьшать период (импульс) с 700us до 20us и смотреть, как получится программа захвата ввода и Arduino BLE и/или последовательные показания.. Возможно, в состоянии определить, есть ли ограничение программного обеспечения., @TommyS
Используя генератор freq, кажется, что программа висит на отметке 500us и ниже с 10%-ной скважностью волны около 1,9 кГц. Я внес некоторые временные изменения в программу, где она просто выделяет необработанные данные...и смогла снизиться до 15us импульсов. Все еще проверяю..., @TommyS
Все спецификации для скорости opamp даны, предполагая линейную область opamp, что здесь не так, выход opamp, как вы видите, ограничен 0 В и 3,3 В, что также делает zenner бесполезным. Попробуйте заменить R27 на более высокое значение, пока не получите чистый, не ограниченный выход, затем используйте компаратор или просто используйте только компаратор без opamp., @Dorian
Также что-то действительно странно с выходом компаратора, конечно, что-то не так в том, как вы используете компаратор. Этот компаратор имеет гистерезис, я не могу понять, как вы попали на эти графики., @Dorian