Как узнать частоту дискретизации?
Я начинаю немного путаться в частотах дискретизации, скорости передачи данных и т. д. У меня есть этот код Arduino:
#include <eHealth.h>
extern volatile unsigned long timer0_overflow_count;
float fanalog0;
int analog0;
unsigned long time;
byte serialByte;
void setup() {
Serial.begin(9600);
}
void loop() {
while (Serial.available()>0){
serialByte=Serial.read();
if (serialByte=='S'){
while(1){
fanalog0=eHealth.getECG();
// Используем таймер0 => 1 тик каждые 4 нас
time=(timer0_overflow_count << 8) + TCNT0;
// Преобразование микросекунд.
time=(time*4);
//Печать в файл для симуляции
//Serial.print(время);
//Серийный.print(" ");
Serial.print(fanalog0,5);
Serial.print("\n");
if (Serial.available()>0){
serialByte=Serial.read();
if (serialByte=='F') break;
}
}
}
}
}
Поскольку прерывания по задержке нет, какова частота/частота дискретизации? Это основано на скорости АЦП Arduino? Когда я увеличиваю скорость передачи, я увеличиваю частоту дискретизации или просто скорость, с которой я отправляю данные через последовательный порт?
@user3284376, 👍17
7 ответов
В каждом цикле вы печатаете 8 символов по последовательному каналу со скоростью 9600 бит/с. Каждый символ занимает 10 бит (1 старт, 8 бит на символ, 1 стоп). Это означает, что вы можете проходить этот цикл примерно 120 раз в секунду.
Функция analogRead()
теоретически может выполнять выборку со скоростью около 9600 раз в секунду, реально это около 8600 раз в секунду.
Вы ограничены последовательной связью.
Тактовая частота АЦП Arduino задается в ..arduino-1.5.5\hardware\arduino\avr\cores\arduino\wiring.c
Вот соответствующая часть
#if defined(ADCSRA)
// Установите коэффициент предварительного масштабирования A/D равным 128
// 16 МГц / 128 = 125 кГц, внутри желаемого диапазона 50-200 кГц.
// XXX: это не будет работать должным образом для других тактовых частот, и
// этот код должен использовать F_CPU для определения коэффициента предварительного масштабирования.
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
// Включить аналого-цифровые преобразования
sbi(ADCSRA, ADEN);
#endif
Для Arduino 16 МГц тактовая частота АЦП установлена на 16 МГц/128 = 125 кГц. Каждое преобразование в AVR занимает 13 тактов АЦП, поэтому 125 кГц / 13 = 9615 Гц.
Это максимально возможная частота дискретизации, но фактическая частота дискретизации в вашем приложении зависит от интервала между последовательными вызовами-конверсиями.
Поскольку вы считываете результат и отправляете его через последовательный порт, вы получаете задержку, которая увеличивается по мере уменьшения скорости передачи данных. Чем ниже скорость передачи данных, тем больше времени потребуется для отправки данных той же длины и тем больше времени потребуется для вызова следующего преобразования АЦП.
Действительную частоту дискретизации в вашем приложении можно определить с помощью отладчика или симулятора, но более простым решением является переключение цифрового контакта каждый раз, когда вы выполняете преобразование, и измерение частоты, с которой переключается цифровой контакт.
Кроме того, время между моими отметками времени увеличивается с ~ 1300 до ~ 16400, конечно, они должны оставаться прежними? То есть на 9600, на 115200 они увеличиваются только примерно до 1500 спустя много времени., @user3284376
@user3284376 user3284376 относительно вашего кода отметки времени, я думаю, что он не может работать постоянно (может быть смещен из-за некоторых прерываний в неподходящее время). Я предлагаю вам опубликовать конкретный вопрос о том, как получить высокую точность синхронизации на Arduino, и поместить туда соответствующую часть вашего кода., @jfpoilpret
Я также хотел получить высокую частоту дискретизации для проекта. Оказывается, биты ADPS2, ADPS1, ADPS0 регистра ADCSRA можно настроить для получения частоты дискретизации 76923 с/с или 76,8 кс/с. Но имейте в виду, что я запускаю АЦП моего arduino в автономном режиме, следующие строки сработали для меня.
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
void setup() {
// Установите прескалер на 16 (16000 кГц/16 = 1 МГц)
// ВНИМАНИЕ: 10-битные результаты выше 200 кГц ненадежны.
//ADCSRA |= B00000100;
sbi(ADCSRA, ADPS2);
cbi(ADCSRA, ADPS1);
cbi(ADCSRA, ADPS0);
// Установите ADIE в ADCSRA (0x7A), чтобы разрешить прерывание от АЦП.
// Без этого внутреннее прерывание не сработает.
//ADCSRA |= B00001000;
sbi(ADCSRA,ADIE)
}
При такой частоте обычные 10-битные результаты ненадежны. Это означает, что увеличение частоты дискретизации снизит точность результатов. Поэтому я использую только старшие 8 бит, потому что в этом предскаляре старшие 8 бит надежны. Вы можете более подробно остановиться на этой странице, этот чувак крут! он сделал осциллограф с высокой частотой дискретизации, используя UNO http://www.instructables.com/id/Girino- Быстрый Arduino-осциллограф/
У меня ATMEGA 2560, но я решил скопировать, если это сработает. Как только я заменил вызовы sbi
и cbi
их определениями (они не понравились моему компилятору) И закомментировал последнюю строку, качество моей дурацкой звуковой схемы значительно улучшилось. Спасибо!, @Erhannis
Отправка 11 бит по последовательному порту со скоростью 9600 бод, но для выборки я сохраняю их в массиве с минимально возможной задержкой, а затем, как только это будет сделано, я отправляю их через последовательный порт для чтения Python. сценарий. Я делаю это для БПФ, используя matplotlib. Я слушаю сигнал 0–5 В, затем, не используя функцию delay(), сохраняю значения AnalogRead() в этот массив. За долю секунды выполняется чтение, затем начинается последовательный дамп данных. Когда я откалибровал входную частоту с помощью тона () от другого подключенного Arduino, я понял, что мне нужно разделить индекс на 8915, чтобы получить точность в пределах 0,1 Гц. Поскольку для получения правильных индексных интервалов нужно было бы разделить на частоту дискретизации, я предполагаю, что частота дискретизации Arduino (по крайней мере, моя с моим кодом) составляет 8915 Гц.
Ссылаясь на часть о разнице между частотой дискретизации и скоростью передачи, это разные измерения.
Частота дискретизации — это частота, с которой устройство (arduino) может воссоздавать цифровое представление входящих аналоговых значений.
Скорость передачи — это скорость, с которой информация передается по каналу связи. Он описывает скорость связи между микроконтроллером и внешним миром (компьютером).
Я бы рекомендовал эту ссылку electronics_stack_exchange. https://electronics.stackexchange.com/questions/135056/sampling-rate- скорость передачи данных и пропускная способность
8915Гц - это очень близко к 125000/14 ~= 8928.6 Мое первоначальное предположение, что между соседними конверсиями требуется ровно один промежуток. Один такт АЦП для выборки и 13 тактовых импульсов АЦП для самого преобразования. Небольшая ошибка может быть следствием несовершенного источника тактового сигнала Arduino. Я пока не уверен. Эта тема для меня сейчас актуальна, так как семплированные данные должны подаваться на цифровой фильтр.
Я не уверен, что вы имеете в виду, когда говорите: «Эта тема актуальна для меня сейчас, так как выборочные данные должны поступать на цифровой фильтр». У вас похожая проблема?, @VE7JRO
Каждое преобразование начинается с переднего фронта тактового сигнала АЦП, и при выполнении кода теряется как минимум один тактовый цикл АЦП. Так что да, 8928,6 Гц — это самое быстрое, что вы можете получить, вызвав analogRead()
в узком цикле, по сравнению с очень стабильными 9615,4 Гц в автономном режиме., @Edgar Bonet
Вы думали о приобретении A Saleae или аналогичного логического анализатора. Простые недорогие прекрасно работают и позволяют довольно легко проводить эти измерения. Это работает лучше, чем область действия в большинстве моих приложений. Если есть перекрытие сигналов, это будет показано. Я просто выделяю один пин для тестирования и называю его тестовым пином. Просто установите его на высокий уровень, когда начинаете процедуру, а затем на низкий, когда закончите. Он имеет 8 входов, поэтому вы можете видеть взаимосвязь между сигналами. Вы можете контролировать АЦП, запуская триггер и размещая serial на другом выводе. У вас еще есть 6 на другие дела. Проведите с ним несколько часов, и он станет одним из ваших самых важных инструментов. Я использую Linux Mint, поэтому я просто держу его на другом экране, поэтому простой щелчок открывает его, и он будет работать независимо от того, находится ли окно в поле зрения или нет. Будьте осторожны, если у вас есть неиспользуемые входы, они будут действовать как антенны и улавливать паразитные сигналы, особенно от импульсных источников питания. Просто выберите нужные каналы или игнорируйте ненужные. Встроенные анализаторы быстро справляются с последовательными сигналами.
- Что такое Serial.begin(9600)?
- Использовать все контакты как цифровые входы/выходы
- Float печатается только 2 десятичных знака после запятой
- Arduino как USB HID
- Serial1' was not declared in this scope
- Очень простая операция Arduino Uno Serial.readString()
- AT-команда не отвечает на последовательный монитор
- Как очистить входной последовательный буфер в Arduino?
Таким образом, увеличение до 115200 дает 1440 раз в секунду, это частота дискретизации?, @user3284376
Дай или возьми, да. Вы должны иметь в виду, что Serial требует ответа на другом конце, поэтому вы зависите от ответа ПК. Это не детерминировано, поэтому вы получите джиттер., @Cybergibbons
Вы правы насчет Arduino, все выглядит хорошо, но на Python все намного медленнее, что мне нужно сделать, чтобы повысить производительность на компьютере?, @user3284376
Вам нужно смотреть на это не как на проблему с последовательной производительностью на ПК, а на то, как отделить выборку от отправки данных., @Cybergibbons
@Cybergibbons - нет, поскольку это работает на Uno, где USB и серийный номер развязаны, нет никакой зависимости от ПК, кроме выдачи символа «S» и отсутствия выдачи «F». Скетч, размещенный здесь, и платформа, на которой он работает, с радостью передают последовательные данные в сопутствующий USB-последовательный микроконтроллер, слепо не обращая внимания на то, что тот или что-либо на другом конце USB не отстает., @Chris Stratton