সুচিপত্র:

ডিটিএমএফ ডিটেক্টর: 4 টি ধাপ
ডিটিএমএফ ডিটেক্টর: 4 টি ধাপ
Anonim
Image
Image

ওভারভিউ

ডিজিটাল সিগন্যাল প্রসেসিং অনলাইন কোর্সে হোম অ্যাসাইনমেন্টের মাধ্যমে আমি এই ডিভাইসটি তৈরি করতে অনুপ্রাণিত হয়েছিলাম। এটি একটি ডিটিএমএফ ডিকোডার যা আরডুইনো ইউএনও দিয়ে প্রয়োগ করা হয়েছে, এটি ফোনের কীপ্যাডে টোন মোডে চাপা একটি অঙ্ক সনাক্ত করে যা এটি উত্পাদিত শব্দ দ্বারা।

ধাপ 1: অ্যালগরিদম বোঝা

কোড
কোড

ডিটিএমএফ -এ প্রতিটি প্রতীকটি ছবির টেবিল অনুযায়ী দুটি ফ্রিকোয়েন্সি দিয়ে এনকোড করা হয়েছে।

ডিভাইসটি মাইক্রোফোন থেকে ইনপুট ক্যাপচার করে এবং আটটি ফ্রিকোয়েন্সি এর প্রশস্ততা গণনা করে। সর্বাধিক প্রশস্ততা সহ দুটি ফ্রিকোয়েন্সি একটি সারি এবং এনকোডেড চিহ্নের একটি কলাম দেয়।

তথ্য অর্জন

বর্ণালী বিশ্লেষণ করার জন্য নমুনা একটি নির্দিষ্ট অনুমানযোগ্য ফ্রিকোয়েন্সি ক্যাপচার করা উচিত। এটি অর্জনের জন্য আমি সর্বাধিক নির্ভুলতার সাথে বিনামূল্যে চালিত ADC মোড ব্যবহার করেছি (prescaler 128) এটি নমুনা হার 9615Hz দেয়। নীচের কোডটি দেখায় কিভাবে Arduino এর ADC কনফিগার করতে হয়।

অকার্যকর initADC () {

// ইনিশ এডিসি; f = (16MHz/prescaler)/13 চক্র/রূপান্তর ADMUX = 0; // চ্যানেল সেল, রাইট-অ্যাড, AREF পিন ADCSRA = _BV (ADEN) | ব্যবহার করুন // ADC সক্ষম _BV (ADSC) | // ADC start _BV (ADATE) | // অটো ট্রিগার _BV (ADIE) | // ইন্টারাপ্ট সক্ষম _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // ফ্রি-রান মোড DIDR0 = _BV (0); // ADC পিনের জন্য ডিজিটাল ইনপুট বন্ধ করুন TIMSK0 = 0; // টাইমার 0 অফ} এবং ইন্টারাপ্ট হ্যান্ডলার দেখতে এই ISR (ADC_vect) {uint16_t sample = ADC; নমুনা [samplePos ++] = নমুনা - 400; যদি (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // বাফার পূর্ণ, বাধা বন্ধ}}

বর্ণালী বিশ্লেষণ

নমুনা সংগ্রহের পর আমি 8 ফ্রিকোয়েন্সি এনকোডিং প্রতীকগুলির প্রশস্ততা গণনা করি। এর জন্য আমার সম্পূর্ণ এফএফটি চালানোর দরকার নেই, তাই আমি গোয়ার্টজেলের অ্যালগরিদম ব্যবহার করেছি।

অকার্যকর গোয়ারজেল (uint8_t *নমুনা, ভাসা *বর্ণালী) {

ভাসা v_0, v_1, v_2; float re, im, amp; জন্য (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); ভাসা a = 2. * c; v_0 = v_1 = v_2 = 0; জন্য (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (নমুনা ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); বর্ণালী [k] = amp; }}

ধাপ 2: কোড

উপরের ছবিটি ডিজিট 3 এর এনকোডিংয়ের উদাহরণ দেখায় যেখানে সর্বোচ্চ প্রশস্ততা 697Hz এবং 1477Hz ফ্রিকোয়েন্সিগুলির সাথে মিলে যায়।

সম্পূর্ণ স্কেচ নিম্নরূপ দেখায়

/** * সংযোগ: * [মাইক থেকে আরডুইনো] * - আউট -> A0 * - Vcc -> 3.3V * - Gnd -> Gnd * - Arduino: AREF -> 3.3V * [Arduino এ প্রদর্শন] * - Vcc - > 5V * - Gnd -> Gnd * - DIN -> D11 * - CLK -> D13 * - CS -> D9 */ #অন্তর্ভুক্ত #অন্তর্ভুক্ত

#অন্তর্ভুক্ত

#সংজ্ঞায়িত করুন CS_PIN 9

#256 সংজ্ঞায়িত করুন

#ডিফাইন IX_LEN 8 #থ্রেশহোল্ড 20 নির্ধারণ করুন

LEDMatrixDriver lmd (1, CS_PIN);

uint8_t নমুনা [N];

volatile uint16_t samplePos = 0;

ভাসমান বর্ণালী [IX_LEN];

// ফ্রিকোয়েন্সি [697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0, 1633.0]

// 9615Hz 256 নমুনার জন্য গণনা করা হয় const float cos_t [IX_LEN] PROGMEM = {0.8932243011955153, 0.8700869911087115, 0.8448535652497071, 0.8032075314806449, 0.6895405447370669, 0.6364404, 0.6364404 const float sin_t [IX_LEN] প্রোগ্রাম = {0।

টাইপডেফ স্ট্রাকচার {

চার অঙ্ক; uint8_t সূচক; } digit_t;

digit_t সনাক্ত_ডিজিট;

const char টেবিল [4] [4] প্রোগ্রাম = {

{'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', ' C '}, {'*',' 0 ','#',' D '}};

const uint8_t char_indexes [4] [4] প্রোগ্রাম = {

{1, 2, 3, 10}, {4, 5, 6, 11}, {7, 8, 9, 12}, {15, 0, 14, 13} };

বাইট ফন্ট [16] [8] = {

{0x00, 0x38, 0x44, 0x4c, 0x54, 0x64, 0x44, 0x38}, // 0 {0x04, 0x0c, 0x14, 0x24, 0x04, 0x04, 0x04, 0x04}, // 1 {0x00, 0x30, 0x48, 0x44, 0x04, 0x38, 0x40, 0x7c}, // 2 {0x00, 0x38, 0x04, 0x04, 0x18, 0x04, 0x44, 0x38}, // 3 {0x00, 0x04, 0x0c, 0x14, 0x24, 0x7e, 0x04, 0x04, 0x04 }, // 4 {0x00, 0x7c, 0x40, 0x40, 0x78, 0x04, 0x04, 0x38}, // 5 {0x00, 0x38, 0x40, 0x40, 0x78, 0x44, 0x44, 0x38}, // 6 {0x00, 0x7c, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10}, // 7 {0x00, 0x3c, 0x44, 0x44, 0x38, 0x44, 0x44, 0x78}, // 8 {0x00, 0x38, 0x44, 0x44, 0x3c, 0x04, 0x04, 0x78}, // 9 {0x00, 0x1c, 0x22, 0x42, 0x42, 0x7e, 0x42, 0x42}, // A {0x00, 0x78, 0x44, 0x44, 0x78, 0x44, 0x44, 0x7c}, / / বি {0x00, 0x3c, 0x44, 0x40, 0x40, 0x40, 0x44, 0x7c}, // C {0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78}, // D {0x00, 0x0a, 0x7f, 0x14, 0x28, 0xfe, 0x50, 0x00}, // # {0x00, 0x10, 0x54, 0x38, 0x10, 0x38, 0x54, 0x10} // *};

অকার্যকর initADC () {

// ইনিশ এডিসি; f = (16MHz/prescaler)/13 চক্র/রূপান্তর ADMUX = 0; // চ্যানেল সেল, রাইট-অ্যাড, AREF পিন ADCSRA = _BV (ADEN) | ব্যবহার করুন // ADC সক্ষম _BV (ADSC) | // ADC start _BV (ADATE) | // অটো ট্রিগার _BV (ADIE) | // ইন্টারাপ্ট সক্ষম _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0); // 128: 1/13 = 9615 Hz ADCSRB = 0; // ফ্রি-রান মোড DIDR0 = _BV (0); // ADC পিনের জন্য ডিজিটাল ইনপুট বন্ধ করুন TIMSK0 = 0; // টাইমার 0 বন্ধ}

অকার্যকর গোয়ারজেল (uint8_t *নমুনা, ভাসা *বর্ণালী) {

ভাসা v_0, v_1, v_2; float re, im, amp; জন্য (uint8_t k = 0; k <IX_LEN; k ++) {float c = pgm_read_float (& (cos_t [k])); float s = pgm_read_float (& (sin_t [k])); ভাসা a = 2. * c; v_0 = v_1 = v_2 = 0; জন্য (uint16_t i = 0; i <N; i ++) {v_0 = v_1; v_1 = v_2; v_2 = (float) (নমুনা ) + a * v_1 - v_0; } re = c * v_2 - v_1; im = s * v_2; amp = sqrt (re * re + im * im); বর্ণালী [k] = amp; }}

ভাসমান গড় (float *a, uint16_t len) {

ভাসা ফলাফল =.0; জন্য (uint16_t i = 0; i <len; i ++) {result+= a ; } ফলাফল / len; }

int8_t get_single_index_above_threshold (float *a, uint16_t len, float threshold) {

যদি (থ্রেশহোল্ড <THRESHOLD) {return -1; } int8_t ix = -1; জন্য (uint16_t i = 0; i থ্রেশহোল্ড) {যদি (ix == -1) {ix = i; } অন্য {রিটার্ন -1; }}} রিটার্ন ix; }

void detect_digit (float *spectrum) {

float avg_row = গড় (বর্ণালী, 4); float avg_col = avg (& spectrum [4], 4); int8_t সারি = get_single_index_above_threshold (বর্ণালী, 4, গড়_রো); int8_t col = get_single_index_above_threshold (& spectrum [4], 4, avg_col); যদি (সারি! = -1 && col! = -1 && avg_col> 200) {detect_digit.digit = pgm_read_byte (& (table [row] [col])); detect_digit.index = pgm_read_byte (& (char_indexes [সারি] [col])); } অন্যথায় {detect_digit.digit = 0; }}

অকার্যকর ড্র স্প্রাইট (বাইট* স্প্রাইট) {

// মাস্কটি স্প্রাইট রো বাইট মাস্ক = B10000000 থেকে কলাম বিট পেতে ব্যবহৃত হয়; জন্য (int iy = 0; iy <8; iy ++) {for (int ix = 0; ix <8; ix ++) {lmd.setPixel (7 - iy, ix, (bool) (sprite [iy] & mask));

// ডানদিকে একটি পিক্সেল দ্বারা মাস্কটি স্থানান্তর করুন

মুখোশ = মুখোশ >> 1; }

// রিসেট কলাম মাস্ক

মাস্ক = B10000000; }}

অকার্যকর সেটআপ() {

cli (); initADC (); sei ();

Serial.begin (115200);

lmd.setEnabled (সত্য); lmd.setIntensity (2); lmd.clear (); lmd.display ();

detect_digit.digit = 0;

}

স্বাক্ষরবিহীন দীর্ঘ z = 0;

অকার্যকর লুপ () {

যখন (ADCSRA & _BV (ADIE)); // গোয়ার্টজেল (নমুনা, বর্ণালী) শেষ করার জন্য অডিও স্যাম্পলিংয়ের জন্য অপেক্ষা করুন; detect_digit (বর্ণালী);

if (detect_digit.digit! = 0) {

drawSprite (ফন্ট [detect_digit.index]); lmd.display (); } যদি (z % 5 == 0) {for (int i = 0; i <IX_LEN; i ++) {Serial.print (বর্ণালী ); Serial.print ("\ t"); } Serial.println (); Serial.println ((int) detect_digit.digit); } z ++;

নমুনা পস = 0;

ADCSRA | = _BV (ADIE); // পুনরায় শুরু নমুনা বিঘ্ন

}

ISR (ADC_vect) {

uint16_t নমুনা = ADC;

নমুনা [samplePos ++] = নমুনা - 400;

যদি (samplePos> = N) {ADCSRA & = ~ _BV (ADIE); // বাফার পূর্ণ, বাধা বন্ধ}}

ধাপ 3: স্কিম্যাটিক্স

স্কিম্যাটিক্স
স্কিম্যাটিক্স

নিম্নলিখিত সংযোগগুলি করা উচিত:

Arduino থেকে মাইক

আউট -> A0

Vcc -> 3.3V Gnd -> Gnd

AREF কে 3.3V এর সাথে সংযুক্ত করা গুরুত্বপূর্ণ।

Arduino প্রদর্শন

Vcc -> 5V

Gnd -> Gnd DIN -> D11 CLK -> D13 CS -> D9

ধাপ 4: উপসংহার

এখানে কি উন্নতি করা যেতে পারে? আমি 9615Hz রেটে N = 256 নমুনা ব্যবহার করেছি যার কিছু বর্ণালী ফুটো আছে, যদি N = 205 এবং হার 8000Hz হয় তবে পছন্দসই ফ্রিকোয়েন্সিগুলি বিচ্ছিন্নতা গ্রিডের সাথে মিলে যায়। তার জন্য এডিসি টাইমার ওভারফ্লো মোডে ব্যবহার করা উচিত।

প্রস্তাবিত: