جدول المحتويات:

EasyFFT: تحويل فورييه السريع (FFT) لأردوينو: 6 خطوات
EasyFFT: تحويل فورييه السريع (FFT) لأردوينو: 6 خطوات

فيديو: EasyFFT: تحويل فورييه السريع (FFT) لأردوينو: 6 خطوات

فيديو: EasyFFT: تحويل فورييه السريع (FFT) لأردوينو: 6 خطوات
فيديو: Fast Fourier Transform using the ARM CMSIS Library within the STM32 MCUs 2024, شهر نوفمبر
Anonim
Image
Image

يمكن أن يكون قياس التردد من الإشارة الملتقطة مهمة صعبة ، خاصة على Arduino حيث أن لديها طاقة حسابية أقل. هناك طرق متاحة لالتقاط عبور الصفر حيث يتم التقاط التردد عن طريق التحقق من عدد المرات التي تعبر فيها الإشارة خطوط الصفر خلال الوقت المحدد. قد لا تعمل مثل هذه الطريقة عندما تكون الإشارة عبارة عن مجموعة من الترددات المختلفة.

هذا أمر صعب إلى حد ما إذا لم تكن من هذه الخلفية. ولكن كونه أداة ترقيع ، قد يكون هذا الرمز مفيدًا للغاية للعديد من المشاريع المتعلقة بالموسيقى وتحليل الإشارة. كان الدافع من هذا المشروع هو إعداد رمز يسهل تنفيذه على Arduino دون الدخول في خلفيته.

لا يشرح هذا المشروع عمل FFT ولكنه يشرح تطبيق وظيفة FFT. تم شرح نفس العملية أيضًا في الفيديو المرفق.

إذا كنت مهتمًا فقط بتطبيق الكود وليس في شرح له. يمكنك التخطي مباشرة إلى الخطوة رقم 3.

الخطوة 1: مقدمة في تحويل التردد

مقدمة في تحويل التردد
مقدمة في تحويل التردد
مقدمة في تحويل التردد
مقدمة في تحويل التردد

يمكن أن تتكون أي إشارة من مجموعة من الموجات الجيبية المختلفة. لذلك يمكن أيضًا عرض أي إشارة قائمة على الوقت كمزيج من الجيب المتنوع ذي السعات المختلفة.

حاولت شرح عمل DFT (تحويل فورييه المنفصل) في أحد التعليمات السابقة (https://www.instructables.com/id/Arduino-Frequency…). هذه الأساليب بطيئة للغاية لأي تطبيق في الوقت الفعلي. مما يجعلها عديمة الفائدة تقريبًا.

في الصورة ، يتم عرض إشارة وهي مزيج من ترددين f2 و f5. يتم ضرب هذه الإشارة باختبار موجات جيبية للقيم من f1 إلى f5.

يمكن أن يُظهر رياضياً أن - مجموع ضرب مجموعتين من البيانات التوافقية لهما تردد مختلف يميل إلى الصفر (يمكن أن يؤدي العدد الأكبر من البيانات إلى نتيجة الخفقان). في حالتنا ، إذا كان تكرار الضربين لهما نفس التردد (أو قريب جدًا) ، فإن مجموع الضرب هو الرقم غير الصفري.

لذلك إذا تم ضرب إشارتنا في f1 ، فسيكون مجموع الضرب صفرًا (بالقرب من الصفر للتطبيق الحقيقي). مماثل هو الحال بالنسبة f3 ، f4. ومع ذلك ، بالنسبة للقيمة ، لن يكون الناتج f2 و f5 صفراً ، ولكنه أعلى بكثير من باقي القيم.

هنا يتم اختبار إشارة بـ 5 ترددات ، لذلك يجب مضاعفة الإشارة بخمسة ترددات. يستغرق هذا الحساب المكثف وقتًا أطول. يتضح رياضيا أنه بالنسبة لعدد N من العينات ، فإنه يأخذ N * N الضرب المعقد.

الخطوة الثانية: تحويل فورييه السريع

لجعل حساب DFT أسرع ، تم تطوير خوارزمية FFT بواسطة James Cooley و John Tukey. تعتبر هذه الخوارزمية أيضًا واحدة من أهم الخوارزميات في القرن العشرين. يقسم الإشارة إلى جزء فردي وزوجي متسلسل مما يجعل عدد الحسابات المطلوبة أقل. باستخدامه يمكن تقليل إجمالي الضرب المعقد المطلوب إلى NlogN. وهو تحسن كبير.

يمكنك الرجوع أدناه إلى المراجع التي أشرت إليها أثناء كتابة الكود للحصول على فهم مفصل للرياضيات وراء FFT:

1.

2.

3.

4.

الخطوة الثالثة: شرح الكود

1. سرعة الجيب وجيب التمام:

يأخذ حساب FFT قيمة مختلف الجيب وجيب التمام عدة مرات. وظيفة Arduino المدمجة ليست سريعة بما يكفي وتستغرق وقتًا طويلاً لتوفير القيمة المطلوبة. مما يجعل الكود أبطأ بشكل ملحوظ (يضاعف الوقت لـ 64 عينة). لمواجهة هذه المشكلة ، يتم تخزين قيمة الجيب لـ 0 إلى 90 درجة كمضاعفات 255. سيؤدي القيام بذلك إلى التخلص من الحاجة إلى استخدام تخزين الأرقام كعائمة ويمكننا تخزينها على أنها بايت والتي تأخذ 1/4 مساحة على Arduino. يحتاج sine_data إلى اللصق أعلى الكود لإعلانه كمتغير عام.

بصرف النظر عن sine_data ، تم إعلان مصفوفة تسمى f_peaks كمتغير عالمي. بعد كل شوط من وظيفة FFT ، يتم تحديث هذه المجموعة. حيث f_peaks [0] هو التردد الأكثر انتشارًا والقيم الإضافية بترتيب تنازلي.

بايت sine_data [91] = {0، 4، 9، 13، 18، 22، 27، 31، 35، 40، 44، 49، 53، 57، 62، 66، 70، 75، 79، 83، 87، 91 ، 96 ، 100 ، 104 ، 108 ، 112 ، 116 ، 120 ، 124 ، 127 ، 131 ، 135 ، 139 ، 143 ، 146 ، 150 ، 153 ، 157 ، 160 ، 164 ، 167 ، 171 ، 174 ، 177 ، 180 ، 183 ، 186 ، 189 ، 192 ، 195 ، 198 ، 201 ، 204 ، 206 ، 209 ، 211 ، 214 ، 216 ، 219 ، 221 ، 223 ، 225 ، 227 ، 229 ، 231 ، 233 ، 235 ، 236 ، 238 ، 240 ، 241 ، 243 ، 244 ، 245 ، 246 ، 247 ، 248 ، 249 ، 250 ، 251 ، 252 ، 253 ، 253 ، 254 ، 254 ، 254 ، 255 ، 255 ، 255 ، 255} ؛ تعويم f_peaks [5] ؛

نظرًا لأننا قمنا بتخزين قيمة الجيب من 0 إلى 90 درجة ، يمكن حساب أي قيمة للجيب أو جيب التمام. تعمل أدناه الجولة الأولى من الرقم إلى صفر فاصلة عشرية وقيمة الإرجاع من البيانات المخزنة. تحتاج هذه الطريقة إلى قسم عائم واحد فقط. يمكن تقليل هذا بشكل أكبر عن طريق تخزين قيم الجيب مباشرة (وليس 255 ضعفًا). لكن هذا يستهلك ذاكرة عالية في Arduino.

يؤدي استخدام الإجراء أعلاه إلى تقليل الدقة ولكنه يحسن السرعة. بالنسبة لـ 64 نقطة ، فإنه يعطي ميزة 8 مللي ثانية و 128 نقطة يمنحك ميزة 20 مللي ثانية.

الخطوة 4: شرح الكود: وظيفة FFT

يمكن إجراء FFT فقط لحجم العينة 2 ، 4 ، 8 ، 16 ، 32 ، 64 وما إلى ذلك. إذا كانت القيمة ليست 2 ^ n ، فسيأخذ الجانب السفلي من القيمة. على سبيل المثال ، إذا اخترنا حجم العينة 70 ، فسوف يأخذ بعين الاعتبار أول 64 عينة فقط ونهمل الباقي.

يوصى دائمًا أن يكون حجم العينة 2 ^ n. التي يمكن أن تكون:

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, …

سيأخذ طائرتان out_r و out_im قدرًا كبيرًا من الذاكرة. بالنسبة إلى Arduino nano لن يعمل مع عينات أعلى من 128 (وفي بعض الحالات 128) بسبب نقص الذاكرة المتاحة.

بيانات int غير موقعة [13] = {1، 2، 4، 8، 16، 32، 64، 128، 256، 512، 1024، 2048} ؛

int a ، c1 ، f ، o ، x ؛ أ = ن ؛ لـ (int i = 0؛ i <12؛ i ++) // حساب المستويات {if (data <= a) {o = i؛}} int in_ps [data [o] = {}؛ // إدخال لتسلسل float out_r [data [o] = {} ؛ // جزء حقيقي من تحويل float out_im [data [o] = {} ؛ // جزء تخيلي من التحويل

مزيد من التدفق على النحو التالي:

1. ينشئ الرمز ترتيبًا معكوسًا قليلاً لحجم العينة المحدد (تفاصيل حول عكس البت في المراجع: الخطوة 2)

2. إدخال البيانات المطلوبة حسب الأمر الذي تم إنشاؤه ،

3. أداء FFT

4. سعة العدد المركب المحسوبة ،

5. يتم الكشف عن القمم وترتيبها بترتيب تنازلي

6. يمكن الوصول إلى النتائج من f_peaks.

[للوصول إلى البيانات الأخرى (بصرف النظر عن تردد الذروة) يجب تعديل الشفرة ، بحيث يمكن نسخ المتغير المحلي إلى متغير عالمي محدد مسبقًا]

الخطوة الخامسة: اختبار الكود

اختبار الكود
اختبار الكود
اختبار الكود
اختبار الكود

يتم إعطاء عينة من موجة المثلث كمدخلات. لأن تردد أخذ العينات من الموجة هو 10 هرتز وتردد الموجة نفسها هو 1.25 هرتز.

كما يتضح من الناتج الخام ، تتطابق القيمة مع FFT المحسوبة بواسطة Scilab. ومع ذلك ، فإن هذه القيم ليست بالضبط نفس الدقة المنخفضة ولكن موجة جيبية أسرع.

في تردد مجموعة تردد الخرج هي 1.25 و 3.75. ليس من الضروري الحصول على القيمة الدقيقة في كل مرة. عادةً ما تسمى هذه الأرقام صناديق التردد. لذلك قد تكون قيمة الإخراج في أي مكان داخل الحاويات المحددة.

سرعة:

بالنسبة إلى Arduino nano ، يستغرق الأمر:

16 نقطة: 4 مللي ثانية 32 نقطة: 10 مللي ثانية 64 نقطة: 26 مللي ثانية 128 نقطة: 53 مللي ثانية

الخطوة السادسة: الخاتمة

يمكن استخدام رمز FFT هذا في تطبيقات الوقت الفعلي. حيث يستغرق إكمال الحساب حوالي 30 مللي ثانية. ومع ذلك ، فإن قراره محدود بعدد من العينات. عدد العينة محدود بذاكرة Arduino. باستخدام Arduino Mega أو لوحة أداء أعلى يمكن تحسينها.

إذا كان لديك أي استفسارات أو اقتراحات أو تصحيحات فلا تتردد في التعليق.

تحديث (2/5/21)

التحديثات: // ----------------------------- دالة FFT --------------- ------------------------------- // float FFT (int in ، int N، float Frequency)

تم تغيير نوع بيانات N إلى عدد صحيح (بايت موجود) لدعم> 255 حجم عينة. إذا كان حجم العينة <= 128 ، فيجب استخدام نوع بيانات البايت.

موصى به: