2015-12-04 4 views
6

मेरे earlier question से निम्नलिखित के बाद, मेरा लक्ष्य सी # से डब्लूएवी फ़ाइल में डीटीएमएफ टोन का पता लगाना है। हालांकि, मैं वास्तव में यह समझने के लिए संघर्ष कर रहा हूं कि यह कैसे किया जा सकता है।एक डब्ल्यूएवी फ़ाइल से डीटीएमएफ डीकोडिंग

मैं समझता हूं कि डीटीएमएफ आवृत्तियों के संयोजन का उपयोग करता है, और एक गोर्टज़ेल एल्गोरिदम का उपयोग किया जा सकता है ... किसी भी तरह। मैं एक Goertzel कोड स्निपेट को पकड़ा है और मैं इसे में एक .WAV फ़ाइल धकेल कर की कोशिश की है (फ़ाइल है, जो एक 8KHz मोनो 16-बिट पीसीएम WAV है पढ़ने के लिए NAudio उपयोग करते हुए):

using (WaveFileReader reader = new WaveFileReader(@"dtmftest_w.wav")) 
    { 
     byte[] buffer = new byte[reader.Length]; 

     int read = reader.Read(buffer, 0, buffer.Length); 
     short[] sampleBuffer = new short[read/2]; 
     Buffer.BlockCopy(buffer, 0, sampleBuffer, 0, read/2); 
     Console.WriteLine(CalculateGoertzel(sampleBuffer,8000,16));     
    } 

public static double CalculateGoertzel(short[] sample, double frequency, int samplerate) 
    { 
     double Skn, Skn1, Skn2; 
     Skn = Skn1 = Skn2 = 0; 
     for (int i = 0; i < sample.Length; i++) 
     { 
      Skn2 = Skn1; 
      Skn1 = Skn; 
      Skn = 2 * Math.Cos(2 * Math.PI * frequency/samplerate) * Skn1 - Skn2 + sample[i]; 
     } 
     double WNk = Math.Exp(-2 * Math.PI * frequency/samplerate); 
     return 20 * Math.Log10(Math.Abs((Skn - WNk * Skn1))); 
    } 

मुझे पता है कि मैं कर रहा हूं गलत है: मुझे लगता है कि मुझे बफर के माध्यम से पुन: प्रयास करना चाहिए, और केवल एक समय में एक छोटे हिस्से के लिए गोर्टज़ेल मूल्य की गणना करना - क्या यह सही है?

दूसरा, मैं वास्तव में समझ नहीं पा रहा हूं कि गोर्टज़ेल विधि का आउटपुट मुझे क्या बता रहा है: मुझे दोहरा मिलता है (उदाहरण: 210.985812) लौटा, लेकिन मुझे यह पता नहीं है कि इसकी उपस्थिति और मूल्य ऑडियो फ़ाइल में डीटीएमएफ टोन।

मैंने this उत्तर में संदर्भित पुस्तकालयों सहित उत्तर के लिए हर जगह खोज की है; दुर्भाग्य से, कोड here काम नहीं करता है (जैसा कि साइट पर टिप्पणियों में उल्लेख किया गया है)। TAPIEx द्वारा प्रदान की जाने वाली एक वाणिज्यिक लाइब्रेरी है; मैंने अपनी मूल्यांकन लाइब्रेरी की कोशिश की है और यह वही है जो मुझे चाहिए - लेकिन वे ईमेल का जवाब नहीं दे रहे हैं, जो मुझे वास्तव में अपने उत्पाद को खरीदने के बारे में सावधान करता है।

मुझे बहुत सचेत है कि मुझे एक जवाब की तलाश है जब शायद मुझे सही सवाल नहीं पता है, लेकिन आखिरकार मुझे केवल एक .WAV फ़ाइल में डीटीएमएफ टन खोजने का एक तरीका है। क्या मैं सही लाइनों पर हूं, और यदि नहीं, तो क्या कोई मुझे सही दिशा में इंगित कर सकता है?

संपादित करें: आधार के रूप में @Abbondanza कोड का उपयोग करना, और (संभवतः मौलिक रूप से गलत) धारणा है कि मुझे ऑडियो फ़ाइल के छोटे वर्गों को ड्रिप-फीड करने की आवश्यकता है, अब मेरे पास यह है (बहुत मोटा, सबूत- अवधारणा केवल) कोड:

const short sampleSize = 160; 

using (WaveFileReader reader = new WaveFileReader(@"\\mac\home\dtmftest.wav")) 
     {   
      byte[] buffer = new byte[reader.Length]; 

      reader.Read(buffer, 0, buffer.Length); 

      int bufferPos = 0; 

      while (bufferPos < buffer.Length-(sampleSize*2)) 
      { 
       short[] sampleBuffer = new short[sampleSize]; 
       Buffer.BlockCopy(buffer, bufferPos, sampleBuffer, 0, sampleSize*2); 


       var frequencies = new[] {697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0}; 

       var powers = frequencies.Select(f => new 
       { 
        Frequency = f, 
        Power = CalculateGoertzel(sampleBuffer, f, 8000)    
       }); 

       const double AdjustmentFactor = 1.05; 
       var adjustedMeanPower = AdjustmentFactor*powers.Average(result => result.Power); 

       var sortedPowers = powers.OrderByDescending(result => result.Power); 
       var highestPowers = sortedPowers.Take(2).ToList(); 

       float seconds = bufferPos/(float)16000; 

       if (highestPowers.All(result => result.Power > adjustedMeanPower)) 
       { 
        // Use highestPowers[0].Frequency and highestPowers[1].Frequency to 
        // classify the detected DTMF tone. 

        switch (Convert.ToInt32(highestPowers[0].Frequency)) 
        { 
         case 1209: 
          switch (Convert.ToInt32(highestPowers[1].Frequency)) 
          { 
           case 697: 
            Console.WriteLine("1 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 770: 
            Console.WriteLine("4 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 852: 
            Console.WriteLine("7 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 941: 
            Console.WriteLine("* pressed at " + bufferPos); 
            break; 
          } 
          break; 
         case 1336: 
          switch (Convert.ToInt32(highestPowers[1].Frequency)) 
          { 
           case 697: 
            Console.WriteLine("2 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 770: 
            Console.WriteLine("5 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 852: 
            Console.WriteLine("8 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 941: 
            Console.WriteLine("0 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
          } 
          break; 
         case 1477: 
          switch (Convert.ToInt32(highestPowers[1].Frequency)) 
          { 
           case 697: 
            Console.WriteLine("3 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 770: 
            Console.WriteLine("6 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 852: 
            Console.WriteLine("9 pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
           case 941: 
            Console.WriteLine("# pressed at " + bufferPos + " (" + seconds + "s)"); 
            break; 
          } 
          break; 
        } 
       } 
       else 
       { 
        Console.WriteLine("No DTMF at " + bufferPos + " (" + seconds + "s)"); 
       } 
       bufferPos = bufferPos + (sampleSize*2); 
      } 

यह ऑडैसिटी में देखी गई नमूना फ़ाइल है; मैं DTMF keypresses में जोड़ दिया है कि

enter image description here

pressed- और ... यह लगभग काम करता रहे थे। इसके बाद के संस्करण फ़ाइल से, मैं किसी भी DTMF लगभग ठीक है जब तक नहीं देखना चाहिए 3 सेकंड में, हालांकि, मेरी कोड रिपोर्ट:

9 pressed at 1920 (0.12s) 
1 pressed at 2880 (0.18s) 
* pressed at 3200 
1 pressed at 5120 (0.32s) 
1 pressed at 5440 (0.34s) 
7 pressed at 5760 (0.36s) 
7 pressed at 6080 (0.38s) 
7 pressed at 6720 (0.42s) 
5 pressed at 7040 (0.44s) 
7 pressed at 7360 (0.46s) 
7 pressed at 7680 (0.48s) 
1 pressed at 8000 (0.5s) 
7 pressed at 8320 (0.52s) 

... जब तक यह करने के लिए हो जाता है 3 सेकंड, और फिर इसे करने के लिए बसने के लिए शुरू होता है सही उत्तर: कि 1 दबाया गया था:

7 pressed at 40000 (2.5s) 
# pressed at 43840 (2.74s) 
No DTMF at 44800 (2.8s) 
1 pressed at 45120 (2.82s) 
1 pressed at 45440 (2.84s) 
1 pressed at 46080 (2.88s) 
1 pressed at 46720 (2.92s) 
4 pressed at 47040 (2.94s) 
1 pressed at 47360 (2.96s) 
1 pressed at 47680 (2.98s) 
1 pressed at 48000 (3s) 
1 pressed at 48960 (3.06s) 
4 pressed at 49600 (3.1s) 
1 pressed at 49920 (3.12s) 
1 pressed at 50560 (3.16s) 
1 pressed at 51520 (3.22s) 
1 pressed at 52160 (3.26s) 
4 pressed at 52480 (3.28s) 

अगर मैं AdjustmentFactor 1.2 परे तक सामने लाना, मैं बिल्कुल भी बहुत कम पता लगाने मिलता है।

मुझे लगता है कि मैं लगभग वहां हूं, लेकिन क्या कोई यह देख सकता है कि मैं क्या खो रहा हूं?

EDIT2: उपरोक्त परीक्षण फ़ाइल here उपलब्ध है।adjustedMeanPower उदाहरण में ऊपर 47.6660450354638 है, और शक्तियां हैं:

enter image description here

+0

डीटीएमएफ टोम कम से कम 40 मिमी लंबी जगह के साथ कम से कम 40 मिमी होना चाहिए। देखें http://www.genave.com/dtmf-mark-space.htm –

+0

http: //www.genave के अनुसार आपको जिन आवृत्तियों को पहचानने की आवश्यकता है वे 697Hz, 770Hz, 852Hz, 941Hz, 1209Hz, 1336Hz और 1477Hz हैं। com/dtmf.htm –

+0

मैंने अपने उत्तर में एक कोड स्निपेट जोड़ा। अगर आपको आपकी समस्या पर प्रगति करने में मदद मिली तो मुझे बताएं। –

उत्तर

6

CalculateGoertzel() रिटर्न शक्ति प्रदान की नमूना भीतर चयनित आवृत्ति की

प्रत्येक डीटीएमएफ आवृत्तियों (697, 770, 852, 9 41, 120 9, 1336, और 1477 हर्ट्ज) के लिए इस शक्ति की गणना करें, परिणामी शक्तियों को क्रमबद्ध करें और उच्चतम दो चुनें। यदि दोनों एक निश्चित दहलीज से ऊपर हैं तो एक डीटीएमएफ स्वर का पता चला है।

जो आप थ्रेसहोल्ड के रूप में उपयोग करते हैं, वह आपके नमूने के शोर अनुपात (एसएनआर) के संकेत पर निर्भर करता है। शुरुआत के लिए यह सभी गोर्ज़ेल मूल्यों के माध्य की गणना करने के लिए पर्याप्त होना चाहिए, एक कारक (उदाहरण 2 या 3) द्वारा माध्य को गुणा करें, और जांचें कि दो उच्चतम गोर्ज़ेल मान उस मान से ऊपर हैं या नहीं। 1.0 के AdjustmentFactor साथ

var frequencies = new[] {697.0, 770.0, 852.0, 941.0, 1209.0, 1336.0, 1477.0}; 

var powers = frequencies.Select(f => new 
{ 
    Frequency = f, 
    Power = CalculateGoerzel(sample, f, samplerate) 
}); 

const double AdjustmentFactor = 1.0; 
var adjustedMeanPower = AdjustmentFactor * powers.Average(result => result.Power); 

var sortedPowers = powers.OrderByDescending(result => result.Power); 
var highestPowers = sortedPowers.Take(2).ToList(); 

if (highestPowers.All(result => result.Power > adjustedMeanPower)) 
{ 
    // Use highestPowers[0].Frequency and highestPowers[1].Frequency to 
    // classify the detected DTMF tone. 
} 

प्रारंभ:

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


अद्यतन # 1

मैं लहर फ़ाइल पर अपने कोड में कुछ बातें की कोशिश की और समायोजित:

मैं Goertzel गणना के बाद गणनीय materialized (प्रदर्शन के लिए महत्वपूर्ण):

var powers = frequencies.Select(f => new 
{ 
    Frequency = f, 
    Power = CalculateGoertzel(sampleBuffer, f, 8000) 
// Materialize enumerable to avoid multiple calculations. 
}).ToList(); 

मैंने थ्रेसहोल्डिंग के समायोजित माध्य का उपयोग नहीं किया। मैं सिर्फ सीमा कहा 100.0 प्रयोग किया है:

if (highestPowers.All(result => result.Power > 100.0)) 
{ 
    ... 
} 

मैं नमूने का आकार (मेरा मानना ​​है कि आप 160 प्रयुक्त) दोगुनी:

int sampleSize = 160 * 2; 

मैं अपने DTMF वर्गीकरण तय की। मैं नेस्टेड शब्दकोशों इस्तेमाल किया सभी संभव मामलों पर कब्जा करने की:

var phoneKeyOf = new Dictionary<int, Dictionary<int, string>> 
{ 
    {1209, new Dictionary<int, string> {{1477, "?"}, {1336, "?"}, {1209, "?"}, {941, "*"}, {852, "7"}, {770, "4"}, {697, "1"}}}, 
    {1336, new Dictionary<int, string> {{1477, "?"}, {1336, "?"}, {1209, "?"}, {941, "0"}, {852, "8"}, {770, "5"}, {697, "2"}}}, 
    {1477, new Dictionary<int, string> {{1477, "?"}, {1336, "?"}, {1209, "?"}, {941, "#"}, {852, "9"}, {770, "6"}, {697, "3"}}}, 
    { 941, new Dictionary<int, string> {{1477, "#"}, {1336, "0"}, {1209, "*"}, {941, "?"}, {852, "?"}, {770, "?"}, {697, "?"}}}, 
    { 852, new Dictionary<int, string> {{1477, "9"}, {1336, "8"}, {1209, "7"}, {941, "?"}, {852, "?"}, {770, "?"}, {697, "?"}}}, 
    { 770, new Dictionary<int, string> {{1477, "6"}, {1336, "5"}, {1209, "4"}, {941, "?"}, {852, "?"}, {770, "?"}, {697, "?"}}}, 
    { 697, new Dictionary<int, string> {{1477, "3"}, {1336, "2"}, {1209, "1"}, {941, "?"}, {852, "?"}, {770, "?"}, {697, "?"}}} 
} 

फोन कुंजी तो साथ लिया गया है:

var key = phoneKeyOf[(int)highestPowers[0].Frequency][(int)highestPowers[1].Frequency]; 

परिणाम सही नहीं हैं, लेकिन कुछ हद तक विश्वसनीय।


अद्यतन # 2

मुझे लगता है मैं समस्या समझ लगता है, लेकिन यह अपने आप को अभी की कोशिश नहीं कर सकते। आप लक्षित आवृत्तियों को सीधे CalculateGoertzel() पर पास नहीं कर सकते हैं। इसे डीएफटी डिब्बे पर केंद्रित करने के लिए सामान्यीकृत किया जाना चाहिए।की गणना शक्तियां इस दृष्टिकोण का प्रयास करते हैं:

var powers = frequencies.Select(f => new 
{ 
    Frequency = f, 
    // Pass normalized frequenzy 
    Power = CalculateGoertzel(sampleBuffer, Math.Round(f*sampleSize/8000.0), 8000) 
}).ToList(); 

इसके अलावा, आप क्रम त्रुटि को कम करने में sampleSize रूप 205 उपयोग करना होगा।


अद्यतन # 3

मैं प्रोटोटाइप फिर से लिखा NAudio के ISampleProvider इंटरफ़ेस है, जो सामान्यीकृत नमूना मान देता है उपयोग करने के लिए (रेंज में float रों [-1.0, 1.0])। इसके अलावा मैंने स्क्रैच से CalculateGoertzel() फिर से लिखा। यह अभी भी प्रदर्शन अनुकूलित नहीं है, लेकिन आवृत्तियों के बीच बहुत अधिक स्पष्ट शक्ति अंतर देता है। कोई अधिक गलत सकारात्मक हैं जब मैं इसे अपना परीक्षण डेटा चलाता हूं। मैं अत्यधिक आप इसे पर एक नज़र डालें अनुशंसा करते हैं: http://pastebin.com/serxw5nG


अद्यतन # 4

मैं जीना (कब्जा) ऑडियो और पूर्व दर्ज ऑडियो फाइलों में DTMF टोन पता लगाने के लिए एक GitHub project और two NuGet packages बनाया।

+1

अद्यतन # 2 मेरे लिए काम नहीं किया, मुझे डर है; मुझे परीक्षण फ़ाइल से कोई परिणाम नहीं मिला। हालांकि, अद्यतन # 1 में कोड पूरी तरह से काम करता है (लगभग) पूरी तरह से, मेरे उद्देश्यों के लिए निश्चित रूप से पर्याप्त है। आपकी मदद के लिए बहुत बहुत धन्यवाद, मैं इसे तुम्हारे बिना समझ नहीं पाया होता! – KenD

+0

अद्यतन # 3 बेकार ढंग से काम करता है, फिर से धन्यवाद! – KenD

+0

काम नहीं करता है नमूना आवृत्ति 48000 है। – moose

संबंधित मुद्दे