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

QuickFFT: FFT عالي السرعة لـ Arduino: 3 خطوات
QuickFFT: FFT عالي السرعة لـ Arduino: 3 خطوات

فيديو: QuickFFT: FFT عالي السرعة لـ Arduino: 3 خطوات

فيديو: QuickFFT: FFT عالي السرعة لـ Arduino: 3 خطوات
فيديو: The Remarkable Story Behind The Most Important Algorithm Of All Time 2024, شهر نوفمبر
Anonim
QuickFFT: سرعة عالية FFT لاردوينو
QuickFFT: سرعة عالية FFT لاردوينو

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

في أحد التعليمات الخاصة بي ، أعددت رمزًا لـ FFT يمكن العثور عليه هنا: EasyFFT

كان هذا الرمز قادرًا على أداء FFT لما يصل إلى 128 عينة على Arduino nano. رقم عينة أكبر من هذا غير ممكن بسبب ذاكرة Arduino المحدودة. لقد قمت بتعديل الوظيفة قليلاً لتحسين السرعة وتقليل استهلاك الذاكرة. يسمح هذا التعديل لـ Arduino بأداء FFT أسرع بخمس مرات ويستهلك نصف الذاكرة تقريبًا. لا يغطي هذا Instructable عمل FFT ، ويمكن العثور على مراجع له في EasyFFT.

الخطوة 1: العمل

عمل
عمل
عمل
عمل
عمل
عمل
عمل
عمل

تم تعديل وظيفة FFT النموذجية لتحسين السرعة بدقة أقل. كما هو موضح في الصورة ، يجب ضرب إشارة الاختبار بواسطة أشكال الموجة الجيبية أو جيب التمام. يمكن أن تتراوح هذه القيم بين 0 و 1 ، لذا فإن إجراء الضرب العائم أمر لا بد منه. في Arduino ، يعد الضرب العائم بطيئًا مقارنة بعمليات الأعداد الصحيحة.

في هذه الوظيفة ، يتم استبدال موجة الجيب / جيب التمام بموجة مربعة. حيث يتعين علينا مضاعفة إشارة الاختبار بموجة مربعة قد يكون لها قيمة 0 أو 1 أو -1. نتيجة لذلك ، يمكننا استبدال الضرب العائم بجمع أو طرح عدد صحيح. بالنسبة إلى عدد صحيح من Arduino ، يكون الجمع أو الطرح أسرع بحوالي 5 مرات. هذا يجعل الحل أسرع بحوالي 5 مرات.

بسبب هذا التعديل ، يمكن الآن تخزين قيم حاوية التردد كعدد صحيح (كان سابقًا عائمًا) ونحصل على ميزة أخرى تتمثل في انخفاض استهلاك الذاكرة. في Arduino Nano ، يستهلك int 2 بايت من الذاكرة بينما يستهلك float 4 بايت من الذاكرة. نظرًا لهذه الميزة في الكود الجديد ، يمكننا إجراء FFT لما يقرب من 256 عينة (128 عينة سابقًا).

في Normal FFT ، احتجنا إلى تخزين قيمة الجيب لجعل الحل أسرع. في وظيفة جديدة ، نظرًا لأننا لم نعد بحاجة إلى قيم الجيب / جيب التمام ، يمكننا التخلص منها وحفظ بعض الذاكرة.

تطبيق:

تنفيذ هذه الوظيفة مباشرة إلى الأمام. يمكننا ببساطة نسخ الوظيفة من التعليمات البرمجية. يمكن تنفيذ هذه الوظيفة باستخدام الأمر أدناه:

تعويم f = Q_FFT (بيانات ، 256 ، 100) ؛ في دالة Q_FFT ،

البيانات: هذا المصطلح عبارة عن مصفوفة لها قيم إشارة ، وحجم العينة الموصى به هو 2 ، 4 ، 8 ، 32 ، 64 ، 128 ، 256 ، 512 ، … فصاعدًا. إذا كان حجم العينة لا ينتمي إلى هذه القيم ، فسيتم قصه إلى أقرب جانب سفلي من القيم. على سبيل المثال ، إذا كان حجم العينة 75 من FFT فسيتم إجراء 64 عددًا من العينات. الحد الأقصى لحجم العينة محدود بذاكرة الوصول العشوائي المتوفرة على Arduino.

يحدد المصطلح الثاني عدد العينات في المصفوفة والمصطلح الأخير هو تردد أخذ العينات بالهرتز.

الخطوة 2: الكود

يشرح هذا القسم التعديل الذي تم إجراؤه في رمز EasyFFT الذي يجب مراعاته أثناء إجراء التعديل في الكود ،

1. كما أوضحنا من قبل ، هنا تستخدم الأعداد الصحيحة لعمل FFT. Int في Arduino هو رقم 16 بت ويمكن أن يحتوي على قيم من -32768 إلى 32768. كلما تجاوزت قيمة int هذا النطاق ، فإنها تسبب المشكلة. للقضاء على هذه المشكلة بعد حساب المستوى من أي وقت مضى. إذا تجاوز أي من القيمة 15000 مصفوفة كاملة ، فسيتم قسمة 100. سيمنع هذا تجاوز سعة int.

2. حساب السعة: لحساب السعة ، يجب تربيع الجزء الحقيقي والخيالي ، كما يلزم تربيع الجذر التربيعي للمبلغ. التربيع والجذر التربيعي للدالة يستغرق وقتًا. لجعل العملية أسرع ، سيقوم هذا الرمز ببساطة ببعض مقادير الأجزاء الحقيقية والخيالية. هذا بالتأكيد أقل دقة وقد يؤدي إلى استنتاج خاطئ في بعض الحالات. يمكنك اختيار العودة إلى الطريقة العادية لحساب المقدار ، لكن الأمر سيستغرق وقتًا أطول وتحتاج أيضًا إلى إجراء بعض الترتيبات لتخزين هذه الأرقام.

3. لا يحتوي هذا الرمز على وحدة نمطية لاكتشاف الذروة المتعددة. سيختار ببساطة القيمة ذات السعة القصوى (باستثناء الرقم الأول وهو إزاحة التيار المباشر). إذا كنت بحاجة إلى قمم متعددة ، يمكنك الرجوع إلى رمز EasyFFT وإجراء التعديل المطلوب هنا. في هذه الحالة ، يجب أيضًا الإعلان عن بعض المصفوفات / المتغيرات كمتغير عام.

4. تحتوي الوظيفة على السطر التالي:

unsigned int Pow2 [13] = {1، 2، 4، 8، 16، 32، 64، 128، 256، 512، 1024، 2048} ؛

إعلان المتغيرات المذكورة أعلاه كمتغير عام (لصقها في بداية الكود) سيوفر في مكان ما 1 مللي ثانية من الوقت في كل تنفيذ.

5. على عكس وظيفة EasyFFT ، حيث تم تخزين أعلى 5 قمم في مجموعة محددة مسبقًا. ستعيد هذه الوظيفة قيمة عائمة. تمثل هذه القيمة التردد بأقصى سعة بوحدة هرتز. لذا فإن تمثيل الكود سيبدو مثل هذا.

تعويم f = Q_FFT (بيانات ، 256 ، 100) ؛

6. الكشف عن الذروة: بمجرد العثور على التردد مع السعة القصوى ، تستخدم هذه الوظيفة سعة التردد قبلها وبعدها مباشرة لحساب النتائج الدقيقة. السعة المستخدمة في هذا الحساب هي أيضًا مجموع المقياس (وليس الجذر التربيعي لمجموع المربعات)

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

الفعلي F = (A n-1 * Fn-1 + An-1 * Fn-1 + An-1 * Fn-1) / (An-1 + An + An + 1)

حيث An هي سعة n التردد و Fn-1 هي قيمة التردد.

الخطوة الثالثة: النتائج:

نتائج
نتائج
نتائج
نتائج

يظهر وقت الحل في مقارنة الصورة أعلاه مع EasyFFT. تظهر سرعة ذلك مع المقارنة.

يتم عرض بيانات العينة التي تحتوي على 3 موجات جيبية بترددات مختلفة. تتم مقارنة نتيجة QuickFFT بإخراج Scilab. كما نرى في الصورة ، 3 قمم ذات سعة قصوى تتطابق مع إخراج Scilab. ومع ذلك ، يتكون الناتج من الكثير من الضوضاء ، والتي قد تكون مضللة لبعض التطبيقات. لذلك يُنصح بالتحقق من الكود بشكل صحيح قبل التقدم بطلبك.

أتمنى أن تكون قد وجدت هذا الرمز مفيدًا لمشروعك. في حال وجود أي استفسار أو اقتراح يرجى التعليق.

موصى به: