परिचय

डिजिटल सिग्नल प्रोसेसिंग (डीएसपी) आधुनिक एम्बेडेड सिस्टम की रीढ़ है, जो वास्तविक समय में ऑडियो, वीडियो, टेलीमेट्री और संचार संचालन को सक्षम करती है। डीएसपी कार्यों के लिए कुशल सी कोड लिखना सीधे सिस्टम को थ्रूपुट, बिजली की खपत और विलंबता को प्रभावित करता है। सामान्य प्रयोजन कोड के विपरीत, डीएसपी एल्गोरिदम को सीमित स्मृति और प्रसंस्करण संसाधनों के उपयोग को अधिकतम करते हुए सख्त समय-सीमा के भीतर निष्पादित करना चाहिए। यह गाइड मुख्य सिद्धांतों पर विस्तार करता है और डीएसपी अनुप्रयोगों के लिए उत्पादन-ग्रेड सी कोड लिखने के लिए कार्रवाई योग्य तकनीकों को प्रदान करता है, जो निश्चित-पॉइंट अंकगणित से हार्डवेयर-विशिष्ट अनुकूलन तक।

C में DSP फंडामेंटल को समझना

डीएसपी में गणितीय संचालन जैसे कि फ़िल्टरिंग, परिवर्तन, संदूषण और नमूना संकेतों पर वर्णक्रमीय विश्लेषण शामिल हैं। सी में, प्रोग्रामर डेटा प्रतिनिधित्व और प्रवाह के हर पहलू को नियंत्रित करता है, जो कि नियतात्मक निष्पादन के लिए महत्वपूर्ण है। डीएसपी कोड अक्सर माइक्रोकंट्रोलर या डिजिटल सिग्नल प्रोसेसर पर चलता है जहां हार्डवेयर कसकर युग्मित होता है - उदाहरण के लिए, समर्पित मैक (मल्टीप्लिक-एक्युमुलेट) यूनिट या सिमडी वेक्टर इंजन। लक्ष्य आर्किटेक्चर की स्मृति पदानुक्रम, निर्देश सेट और परिधीय क्षमताओं की गहरी समझ कुशल सी कोड लिखने के लिए आवश्यक है।

DSP कोड की प्रमुख विशेषताएं:

  • ]Repeated arithmetic: multiply-add आपरेशन dominate (जैसे FIR फिल्टर) के साथ छोरों।
  • ]Real-time constraints: प्रत्येक नमूना एक नमूना अवधि के भीतर संसाधित किया जाना चाहिए।
  • डेटा स्ट्रीमिंग:] सतत इनपुट/आउटपुट धाराओं को कुशल बफरिंग और न्यूनतम प्रतिलिपि की आवश्यकता होती है।
  • Memory बैंडविड्थ सीमा: कई डीएसपी एल्गोरिदम कैसे तेजी से डेटा स्थानांतरित किया जा सकता है, न कि अंकगणितीय संचालन द्वारा सीमित हैं।

एक आधारिक संदर्भ के लिए, Anog डिवाइसेस'डीएसपी बेसिक्स] देखें।

फिक्स्ड-पॉइंट आर्थमेटिक: फ्लोटिंग-पॉइंट ओवरहेड के बिना प्रेसिजन

कई डीएसपी प्रोसेसरों में हार्डवेयर फ्लोटिंग पॉइंट यूनिट (FPUs) की कमी होती है या FPUs को धीमा कर देती है। फिक्स्ड पॉइंट अंकगणित एक अंतर्निहित त्रिज्या बिंदु के साथ पूर्णांक संचालन का उपयोग करता है, जो कि नियतात्मक प्रदर्शन और कम बिजली की खपत प्रदान करता है। सबसे आम प्रतिनिधित्व Q नोटेशन है: Qm]. nbit प्रारूप में एक बहुभुजीय अंतर है।

C में फिक्स्ड-पॉइंट ऑपरेशन को कार्यान्वित करना

फिक्स्ड-पॉइंट जोड़ सीधा है (सिप्लीकेशन पूर्णांक जोड़ते हैं), लेकिन गुणन को रेडिक्स पॉइंट को समायोजित करने की आवश्यकता होती है। Q15 गुणन के लिए, दो Q15 संख्याओं के उत्पाद को 32-bit मध्यवर्ती परिणाम की आवश्यकता होती है, फिर आप Q15 पर वापस जाने के लिए 15 बिट्स तक दाहिने-शिफ्ट। उदाहरण:

typedef int16_t q15_t;
q15_t q15_mul(q15_t a, q15_t b) {
 int32_t temp = (int32_t)a * (int32_t)b;
 return (q15_t)(temp >> 15);
}

जब संचय होता है (उदाहरण के लिए, फिल्टर में), गार्ड बिट्स अतिप्रवाह को रोकते हैं। 32-बिट या 64-बिट संचयक और संतृप्त परिणाम का उपयोग करें। फिक्स्ड-पॉइंट पुस्तकालयों जैसे ARM CMSIS-DSP[ फिल्टरिंग, ट्रांसफ़ॉर्म और मैट्रिक्स ऑपरेशन सहित अनुकूलित फिक्स्ड-पॉइंट फंक्शन प्रदान करते हैं।

जब फ्लोटिंग-पॉइंट बनाम फिक्स्ड-पॉइंट का उपयोग किया जाता है

FPUs (जैसे कॉर्टेक्स-M4/M7) के साथ आधुनिक प्रोसेसर फ्लोटिंग पॉइंट ऑपरेशन को स्थिर-पॉइंट के रूप में तेजी से कार्यान्वित कर सकते हैं। जब फ्लोटिंग पॉइंट का उपयोग करें:

  • अल्गोरिथम गतिशील रेंज उच्च है (जैसे अनुकूली फिल्टर)।
  • कोड रखरखाव एक प्राथमिकता है (कम पैमाने पर विश्लेषण)।
  • FPU हार्डवेयर मौजूद है और पाइपलाइन ऐड्स और गुणा को ओवरलैप कर सकती है।

FPUs के बिना उच्च मात्रा के उपकरणों पर, निश्चित बिंदु लागत-संवेदनशील अनुप्रयोगों के लिए मानक बनी हुई है।

DSP के लिए मेमोरी एक्सेस का अनुकूलन

DSP एल्गोरिदम अक्सर डेटा अनुक्रमिक रूप से बड़ी सरणी की प्रक्रिया करते हैं। कैश मिस और बस स्टालों प्रदर्शन को मार सकते हैं। इन सिद्धांतों का पालन करें:

  • ]Linear डेटा पहुँच: परंपरागत क्रम में अनुप्रस्थ सरणी (C में row-major)). जब तक कि एल्गोरिथ्म (जैसे FFT बिट उलट).
  • डेटा संरेखण: सुनिश्चित करें कि सरणी को कैश-लाइन सीमाओं के लिए संरेखित किया गया है। या विशेष स्मृति अनुभाग जैसे compiler विशेषताओं का उपयोग करें।
  • Buffering: सीपीयू प्रसंस्करण के साथ DMA हस्तांतरण को ओवरलैप करने के लिए डबल बफरिंग का उपयोग करें। जबकि सीपीयू एक बफर पर काम करता है, अगले नमूना ब्लॉक लोड किया जा रहा है।
  • Restrict keyword: का उपयोग C99 के ] को इंगित करने वाले को यह सूचित करने के लिए कि पॉइंटर्स ने एलिया नहीं किया है, वेक्टरीकरण को सक्षम किया है और बेहतर निर्देश निर्धारण किया है।

उदाहरण के लिए, इनपुट और आउटपुट बफर अलग होने पर एक साधारण FIR फ़िल्टर फ़ंक्शन को `restrict` के साथ लिखा जाना चाहिए:

void fir_lowpass(const int16_t * restrict x, int16_t * restrict y,
 const int16_t * restrict coeffs, int len, int order) {
 for (int i = 0; i < len; i++) {
 int32_t acc = 0;
 for (int j = 0; j < order; j++) {
 acc += (int32_t)x[i + j] * coeffs[j];
 }
 y[i] = (int16_t)(acc >> 15);
 }
}

कुशल एल्गोरिथ्म चयन और कार्यान्वयन

एल्गोरिथ्मिक जटिलता सीधे निष्पादन समय और शक्ति का अनुवाद करती है। हमेशा कार्य के लिए सबसे कुशल एल्गोरिथ्म चुनें:

  • ]Fast Fourier Transform (FFT): का उपयोग Cooley-Tukey radix-2 या विभाजित-radix के लिए बिजली के दो लंबाई.
  • FIR फिल्टर:] का उपयोग बहुचरण विघटन के लिए उपयोग करें; गुणन की संख्या को हल करने के लिए रैखिक चरण फिल्टर के लिए समरूपता का उपयोग करें।
  • IIR फिल्टर: का उपयोग प्रत्यक्ष रूप II बेहतर संख्यात्मक स्थिरता के लिए transposed; गुणांक मात्राकरण के प्रति संवेदनशीलता को कम करने के लिए कैस्केड द्विquad अनुभागों (दूसरे क्रम चरणों) का उपयोग करें।
  • Convolution: लंबे अनुक्रमों के लिए, प्रत्यक्ष विकास के बजाय FFT आधारित ओवरलैप-एड या ओवरलैप-सेव विधियों का उपयोग करें।

]FFTW पुस्तकालय आधुनिक FFT तकनीकों के संदर्भ में (हालांकि C में नहीं, इसके सिद्धांतों को व्यापक रूप से एम्बेडेड DSP पुस्तकालयों में कॉपी किया जाता है)।

हार्डवेयर सुविधाएँ: SIMD और DSP निर्देश

लगभग सभी आधुनिक माइक्रोकंट्रोलरों में सिमडी (एकल निर्देश एकाधिक डेटा) या डीएसपी-एनहैंस्ड निर्देश शामिल हैं। उदाहरण के लिए:

  • ARM Cortex-M4/M7: SIMD (SADD, SMUAD, आदि), संतृप्त अंकगणित, और आंशिक संचालन (QADD, QSUB)। CMSIS-DSP intrinsic कार्यों का उपयोग करें।
  • टीआई C6000 DSP: आठ गुणा इकाइयों, दोहरी मैक, और सॉफ्टवेयर पाइपलाइन। टीआई DSP अनुकूलन गाइड विस्तृत तकनीक प्रदान करता है।
  • P-extensions के साथ RISC-V: भविष्य कोर में DSP-like निर्देश होंगे।

इन सुविधाओं का उपयोग करने के लिए C में कोड लिखें कि कम्पाइलर ऑटो-vectorize (जैसे, कोई निर्भरता के साथ सरल छोर) कर सकता है या कम्पाइलर आंतरिक कार्यों का उपयोग कर सकता है। उदाहरण के लिए ARM CMSIS-DSP का उपयोग करके FIR फ़िल्टर के लिए किया जाता है:

#include "arm_math.h"
arm_fir_instance_f32 S;
float32_t firState[128];
arm_fir_init_f32(&S, numTaps, coeffs, firState, blockSize);
arm_fir_f32(&S, input, output, blockSize);

इस तरह की पुस्तकालयों को अधिकतम प्रदर्शन के लिए विधानसभा में हाथ से ट्यून किया जाता है। सामान्य सी से पुस्तकालय कार्यों में स्विच करने से पहले और बाद में हमेशा प्रोफ़ाइल।

लूप ऑप्टिमाइज़ेशन तकनीक

चूंकि डीएसपी एल्गोरिदम लूप-भारी हैं, लूप स्तर पर अनुकूलन बड़े लाभांश का भुगतान करते हैं:

  • ]Loop unrolling: मैन्युअल रूप से या compiler pragmas (`#pragma unroll N`) के साथ लूप ओवरहेड को कम करने और निर्देश स्तर समानांतरवाद को बढ़ाने के लिए।
  • सॉफ्टवेयर पाइप लाइनिंग: पुनर्गठन के लिए लूप्स ताकि कई पुनरावृत्तियों एक साथ उड़ान में हो। कुछ compilers इसे स्वचालित रूप से करते हैं; `O3` और वास्तुकला-विशिष्ट झंडे का उपयोग करें।
  • ]Reduce branching: arithmetic (जैसे, मिनट / अधिकतम ternary) के साथ सशर्तों की जगह, या गैर-रैखिक कार्यों के लिए लुकअप टेबल का उपयोग करें।
  • ]Use स्थानीय चर: स्टोर अक्सर लूप के अंदर चर घोषित करके रजिस्टरों में डेटा तक पहुंचता है या `register' संकेत का उपयोग करके।
  • ]]मंत्रियों को न्यूनतम करना: पारस्परिक द्वारा गुणन के साथ विभाजन को बदल देता है; दो की शक्तियों के लिए बदलाव का उपयोग करता है।

Precomputing Constants and lookup tables

डीएसपी कार्यों जैसे त्रिकोणमितीय मान, गुणांक और दो कारकों को ऑफ़लाइन प्रीकॉम्प्यूट किया जाना चाहिए और रॉम में स्थिर सरणी के रूप में संग्रहीत किया जाना चाहिए। गैर-वास्तविक समय के स्टार्टअप के लिए, आप उन्हें एक बार और पुन: उपयोग कर सकते हैं। उदाहरण: 1024-पॉइंट एफएफटी के लिए, प्रत्येक चरण के लिए साइन / कॉसिन मूल्यों को प्रीकॉम्प्यूट करें। यह रनटाइम मूल्यांकन को समाप्त करता है और शक्ति को कम करता है।

लुकअप टेबल (LUTs) भी डेस्कटॉप रूट, एक्सपोनेंट और लॉग जैसे कार्यों के लिए मदद करते हैं, जो डीएसपी (जैसे, भाषण प्रसंस्करण में) में इस्तेमाल किया जाता है। स्मृति बनाम सटीकता के व्यापार के लिए टेबल प्रविष्टियों के बीच रैखिक अंतर का उपयोग करें।

रूपरेखा और ट्यूनिंग

बिना किसी माप के कोई आशावाद पूरा नहीं होता है। इन तकनीकों का उपयोग करके बोतल की गर्दन की पहचान की जाती है:

  • Cycle-accurate profiling: समारोह अवधि को मापने के लिए ऑनबोर्ड चक्र काउंटर (जैसे, DWT CYCCNT) का उपयोग करें।
  • Statistical profiling: नमूना कार्यक्रम काउंटर (PC) यह देखने के लिए कि कौन से कार्य सीपीयू समय का उपभोग करते हैं।
  • Memory profiling: कैश मिस (यदि उपलब्ध हो) और बस लेनदेन की निगरानी के लिए उपकरण का उपयोग करें।
  • Compiler प्रतिक्रिया: सक्षम कम्पाइलर अनुकूलन रिपोर्ट (GCC में `-Fpt-info-vec-optimized`) यह देखने के लिए कि क्या लूप वेक्टरकृत किए गए थे।

Iterate: फिर से माप, परिवर्तन, माप। अक्सर सबसे बड़ा लाभ नाटकीय रूप से varithmetic के बजाय स्मृति पहुंच पैटर्न में सुधार से आता है।

व्यावहारिक सारांश: यह सब मिलकर

C में कुशल डीएसपी कोड लिखने के लिए एक समग्र दृष्टिकोण की आवश्यकता होती है:

  • सही डेटा प्रतिनिधित्व (फिक्स्ड-पॉइंट बनाम फ्लोटिंग-पॉइंट) चुनें।
  • अनुक्रमिक पहुंच और संरेखण के लिए डेटा संरचनाओं को डिजाइन करना।
  • निम्न जटिलता (FFT, polyphase) के साथ एल्गोरिदम का चयन करें।
  • उपलब्ध होने पर विक्रेता डीएसपी पुस्तकालयों का उपयोग करें।
  • अनरोल लूप्स और शाखाओं को कम करने।
  • रॉम में प्रीकोम्प्यूट स्थिरांक।
  • प्रोफ़ाइल को लगातार बढ़ाकर कम्पाइलर को मदद करने दें।

इन सिद्धांतों को लागू करके, डेवलपर्स सी की पोर्टेबिलिटी और रखरखाव को बनाए रखने के दौरान हाथ से जुड़े असेंबली के मुकाबले सिग्नल प्रोसेसिंग थ्रूपुट प्राप्त कर सकते हैं। परिणाम विश्वसनीय, वास्तविक समय में डीएसपी सिस्टम है जो आधुनिक एम्बेडेड उत्पादों की मांगों को पूरा करते हैं - सुनवाई एड्स से लेकर 5 जी बेस स्टेशन तक।