Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 20 of 20

Thread: Change sample rate for Audio Adaptor Board for Teensy 3.0 & 3.1 FFT

  1. #1
    Member
    Join Date
    Nov 2014
    Location
    Italy
    Posts
    32

    Change sample rate for Audio Adaptor Board for Teensy 3.0 & 3.1 FFT

    Hi,
    I'm working on the Audio Adaptor Board for Teensy 3.1 using the FFT example of the Audio Library, to perform a frequency analysis of an handmade Kantele .
    I'm trying to detect every single tone of this instrument, trought an 1024 FFT in the range of 40/4000 Hz.
    The example works great but my problem is that with 512 bins of 21,53 Hz width, I cannot obtain the accuracy that i need.
    I would try to modify the sample rate of the ADC from 44.1KHz to an half or less, I've searched for some variable and I found in the AudioStream library (specifically in the AudioStream.h file) the variable AUDIO_SAMPLE_RATE defined at 44117.64706.
    Code:
    #ifndef AudioStream_h
    #define AudioStream_h
    
    #include "Arduino.h"
    
    #define AUDIO_BLOCK_SAMPLES  128
    #define AUDIO_SAMPLE_RATE    44117.64706
    #define AUDIO_SAMPLE_RATE_EXACT 44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256
    from this comment I suppose that this variable is in some way dependent from the CPU SPEED that I can modify from the Teensyduino IDE. But how?
    I didn't find anything about this..

    I start now some experiment modifying the variable and the CPU SPEED, but I will like to understand if I'm on the right way or not.
    Can someone help me?
    Thanks in advance
    G
    Last edited by GeppettoLab; 12-17-2014 at 02:31 PM.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,171
    Changing the sample rate is very difficult.

    First, edit AudioStream.h.

    Then you will need to edit the I2S code. Start here:

    https://github.com/PaulStoffregen/Au...t_i2s.cpp#L196

    More place might also need to be edited. The entire library was designed for only 44100 (or 44117.647) Hz sampling. It's never really been tested at other speeds.

  3. #3
    Member
    Join Date
    Nov 2014
    Location
    Italy
    Posts
    32
    Ok..
    I've tried in the afternoon, and nothing change. I've modified the AUDIO_SAMPLE_RATE variable and the CPU SPEED without results.
    I could try to decimate the audio sample after the sampling. I know that it a waste of computing but I can't see another solution..

    I will try to modify the library.. I'm not so pratical but I will post all my results.
    Thanks!

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,171
    However, you will find FFT has a fundamental trade-off between update speed and frequency resolution. If you decrease the same rate, or increase the number of FFT bins, the result is more resolution, but you get the results less often.

    1024 bins at 44117 Hz is 23.2 milliseconds. The audio library FFT1024 object gives you 50% overlap, so you get new data every 11.6 ms, which represents the windowed average over the prior 23.2 ms.

    As slower update rates, the period of time represented by one FFT output becomes longer, to the point where it probably is not very useful for most musical material.

  5. #5
    Member
    Join Date
    Nov 2014
    Location
    Italy
    Posts
    32
    Quote Originally Posted by PaulStoffregen View Post
    As slower update rates, the period of time represented by one FFT output becomes longer, to the point where it probably is not very useful for most musical material.
    ok, but my real problem is to obtain a better resolution on the low frequency. In this case 21Hz of bin width is too big
    In the range from 200 and 500 Hz some tone differs from the others of 13Hz and I cannot directly recognize it, cause it falls in more then one bin.
    Surely I can check for the armonics, but the resonance of my instruments create different problems..
    Can I compute an FFT on 2048 instead?

    ---
    I have another doubt.. I sample at 44100, than from nyqvist I check the frequency from 0 to 22000. then each bin is 22000/1024= 21Hz width..
    but using a tone generator with a mic and the audio board, a 440HZ frequency falls in the 11th and 12th bin. Are they the representation of 440Hz? for my computing are the representation of 220Hz.
    Where am I doing wrong?

  6. #6
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,222
    Quote Originally Posted by GeppettoLab View Post
    I have another doubt.. I sample at 44100, than from nyqvist I check the frequency from 0 to 22000. then each bin is 22000/1024= 21Hz width..
    but using a tone generator with a mic and the audio board, a 440HZ frequency falls in the 11th and 12th bin. Are they the representation of 440Hz? for my computing are the representation of 220Hz.
    Where am I doing wrong?
    Doing a 1024 point FFT on 44.1 kHz sampling, you have a bin width of 44100/1024 = 43 Hz (512 positive and 512 negative frequencies. So a 440 Hz tone should fall in the 11/12th bin (positive frequency) and 1012-11/12th bin (negative frequency). This is independent of the fact that standard spectra only present 0 to Nyquist.

    Concerning FFT size, as Paul says, there is a trade-off between frequency bin width and temporal resolution. This is not only signal processing but also physics (uncertainty relation), that you cannot simultaneously measure precisely frequency and time. In other words, any acoustic feature that is, say 10 ms long has a bandwidth of at least 100 Hz, or to get a tone precise at 1 Hz the tone must be at least 1 s long and constant (delta_f * delta_t >= 1).

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,171
    With 1024 point FFT at 44100 Hz samples, each bin is approx 43 Hz.

    http://www.pjrc.com/teensy/gui/?info...AnalyzeFFT1024

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,171
    Maybe this will help? TL;DR = FFT is not very good for this....

    http://stackoverflow.com/questions/1...-a-smart-phone

  9. #9
    Senior Member
    Join Date
    Oct 2013
    Location
    Rogersville MO
    Posts
    253
    http://forum.pjrc.com/threads/24793-...ll=1#post48465

    This code needs tweaked to use the latest library code but gives much higher resolution - uses parabolic interpolation on the FFT.

    Have you thought about using analyze_tonedetect in the audio library?

  10. #10
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,222
    Quote Originally Posted by cartere View Post
    http://forum.pjrc.com/threads/24793-...ll=1#post48465

    This code needs tweaked to use the latest library code but gives much higher resolution - uses parabolic interpolation on the FFT.

    Have you thought about using analyze_tonedetect in the audio library?
    figure 7 in http://www.ni.com/white-paper/4844/en/ (referenced in quoted link) shows nicely the influence of windowing (suppressing sidelobes) at the expense of increasing the main lobe.

    Yes, parabolic interpolation of FFT bins may increase the accuracy of determining the frequency of the tone, but the resolution (differentiating two adjacent tones) is determined by the main lobe of the window response (see above mentioned Fig. 7) There are indeed high resolution methods (e.g. autoregression, or MUSIC, etc) but their spectral estimation capability may not be very accurate, as they are more sensitive to noise.

  11. #11
    Member
    Join Date
    Nov 2014
    Location
    Italy
    Posts
    32
    Quote Originally Posted by WMXZ View Post
    Doing a 1024 point FFT on 44.1 kHz sampling, you have a bin width of 44100/1024 = 43 Hz (512 positive and 512 negative frequencies. So a 440 Hz tone should fall in the 11/12th bin (positive frequency) and 1012-11/12th bin (negative frequency). This is independent of the fact that standard spectra only present 0 to Nyquist.
    here it's my mistake!

    Quote Originally Posted by PaulStoffregen View Post
    Maybe this will help? TL;DR = FFT is not very good for this....
    http://stackoverflow.com/questions/1...-a-smart-phone
    This is very helpful and interesting, I will use someone of this methods it to improve my software.
    But now, for my project the fundamental is not so important i need some armonics and I think that FFT is still the best solution.

    Quote Originally Posted by WMXZ View Post
    Concerning FFT size, as Paul says, there is a trade-off between frequency bin width and temporal resolution. This is not only signal processing but also physics (uncertainty relation), that you cannot simultaneously measure precisely frequency and time. In other words, any acoustic feature that is, say 10 ms long has a bandwidth of at least 100 Hz, or to get a tone precise at 1 Hz the tone must be at least 1 s long and constant (delta_f * delta_t >= 1)
    I don't need a fast computation, probably I can try to use a wider buffer to compute a larger part of sound.

    Should I simply increment the AUDIO_BLOCK_SAMPLES in the AudioStream library?

  12. #12
    There is another potential application for a variable sample rate in the audio library.
    I finished a prototype of a wavetable-based oscillator (parallel EEPROM + DAC, driven by teensy 3.1), similar to the Monowave.

    Teensy 3.1 controls MIDI In, bank select, wave select, and a DS1077 to produce the right frequency (which is divided by a 4040 to send the 256 wave samples to the DAC).
    It sounds really good, and plan to improve upon the design by using Paul's audio adapter (and the optional SPI EEPROM).
    If anybody has already done something like this with Paul's audio adapter i would like to exchange notes.

    Happy tinkering !

  13. #13
    Senior Member
    Join Date
    Feb 2013
    Posts
    563
    Quote Originally Posted by alfa66 View Post
    There is another potential application for a variable sample rate in the audio library.
    I finished a prototype of a wavetable-based oscillator (parallel EEPROM + DAC, driven by teensy 3.1), similar to the Monowave.

    Teensy 3.1 controls MIDI In, bank select, wave select, and a DS1077 to produce the right frequency (which is divided by a 4040 to send the 256 wave samples to the DAC).
    It sounds really good, and plan to improve upon the design by using Paul's audio adapter (and the optional SPI EEPROM).
    If anybody has already done something like this with Paul's audio adapter i would like to exchange notes.

    Happy tinkering !
    i think at best you could emulate a monowave. the audio adapter (that is, the codec on there) only supports a couple of (fixed) sample rates, like most or all modern audio codecs (ie 22.05 kHz, 24 kHz, 32 kHz, 44.1kHz, 48 kHz, 96 kHz and a few others); for PPG style / variable sample rate synthesis you might be better off trying with a SPI DAC, as the adafruit waveHC library did.

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,171
    Quote Originally Posted by GeppettoLab View Post
    Should I simply increment the AUDIO_BLOCK_SAMPLES in the AudioStream library?
    There no single, easy-to-edit location to change the audio library sample rate.

    AUDIO_BLOCK_SAMPLES controls the number of samples processed in each block, not the sample rate. Maybe you're thinking of AUDIO_SAMPLE_RATE and AUDIO_SAMPLE_RATE_EXACT in AudioStream.h? Changing those is only the beginning of the work needed to change the library's sample rate.

    Each input and output object is coded to implement 44117.64706 samples per second. The I2S objects use MCLK and LRCLK from the I2S hardware. The others generally use the PDB to generate their timing. Changing the definition in AudioStream.h does NOT cause all these to update. The library was designed to run at a fixed rate, so changing it is not so simple.


    Quote Originally Posted by alfa66 View Post
    I finished a prototype of a wavetable-based oscillator (parallel EEPROM + DAC, driven by teensy 3.1), similar to the Monowave.

    Teensy 3.1 controls MIDI In, bank select, wave select, and a DS1077 to produce the right frequency (which is divided by a 4040 to send the 256 wave samples to the DAC).
    It sounds really good, and plan to improve upon the design by using Paul's audio adapter (and the optional SPI EEPROM).
    If anybody has already done something like this with Paul's audio adapter i would like to exchange notes.
    You probably should look at using the arbitraryWaveform() feature of the waveform synthesis object.

    http://www.pjrc.com/teensy/gui/?info=AudioSynthWaveform

    If you already have a 256 sample waveform, you can probably use this feature to play it at different speeds.

    However, you MUST properly bandwidth limit your waveform when playing at higher frequencies. The waveform object doesn't do this for you. Perhaps a future version should do this?

    If your waveform contains high frequencies and you increase its speed, you'll be increasing those frequencies too when you play it faster then 1 waveform sample for each 1 audio output sample. Any frequency you increase beyond 22.06 kHz aliases back to become horrible distortion.

    I know this frequency aliasing concept can be difficult to understand. I've been bit by it. It is real. When you actually increase the sample rate, for example playing the 256 samples at 60 kHz, you're increasing the total digital bandwidth to 30 kHz, which automatically makes extra room for those higher frequencies in the original material to become inaudible ultrasonic content.

    But when you play those 256 samples faster using the waveform synthesis object, it skips through the 256 samples and uses linear interpolation to map onto the libraries fixed 44.1 kHz sample rate. The total signal bandwidth remains fixed at 22.06 kHz. The linear interpolation does a pretty good job of giving you the right waveform output, but it does not handle the case where you push higher frequency content from the original 256 samples beyond 22.06 kHz.

    The 256 samples you load MUST be low-pass filtered when you play them at higher speeds. If you play the waveform at 2X speed, it must not have any content above 11.03 kHz, because you're doubling its entire bandwidth. If you try to create any sound above 22.06 kHz, it will not magically become unheard ultrasonic signals. It will alias to become horrible distortion.

  15. #15

    aliasing

    >>You probably should look at using the arbitraryWaveform() feature of the waveform synthesis object.

    >>http://www.pjrc.com/teensy/gui/?info=AudioSynthWaveform

    >> If you already have a 256 sample waveform, you can probably use this feature to play it at different speeds.

    >> However, you MUST properly bandwidth limit your waveform when playing at higher frequencies. The waveform >>object doesn't do this for you. Perhaps a future version should do this?

    Hi Paul,
    thank you for your quick reply - yes, I think I do understand aliasing.
    Here is short summary of my thinking:
    1) With variable sampling rate, most of the aliasing will be eliminated by using a good ol' analog filter.
    2) With fixed sampling rate, using interpolation to generate different frequencies, in order to avoid aliasing I will need to store different versions (I was thinking one for every octave) of the same waveform, and band-limit that adequately. But now the amount of memory to store the waveforms could go up by 5x - which is why I am adding the optional SPI EEPROM to your audio shield
    3) Or - and maybe that's what you are thinking - it would be possible to perform a convolution of the interpolated waveform with a good low pass FIR. This is equivalent to 1) in the sense that it will be done in real time - is this what you are planning to do with the Audio Library ?

    Cheers,

  16. #16
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,171
    Quote Originally Posted by alfa66 View Post
    But now the amount of memory to store the waveforms could go up by 5x - which is why I am adding the optional SPI EEPROM to your audio shield
    Each copy is only 512 bytes. Just use "const" and they'll go into only flash memory. 10 copies is only 5K out of 256K.

  17. #17
    Junior Member
    Join Date
    Dec 2015
    Posts
    19
    Would porting this work?

    HTML Code:
    https://github.com/adafruit/WaveHC
    I'm trying to get this lib to work with the Teensy audio card so that I can change samplerates on the fly using a pot.

    So far, no such luck.

  18. #18
    Junior Member
    Join Date
    Jan 2017
    Posts
    1
    Hi there, I'm working on a audio project as a part of a final B.S. project in mechatronics engineering and using a teensy as a test platform. Same as the OP I need better resolution per bin for FFT diagnosis, and was able to lower the kHz manually by changing :
    #define AUDIO_SAMPLE_RATE 17045.45454
    #define AUDIO_SAMPLE_RATE_EXACT 17045.45454 // 96 MHz * 1 (MCLK_MULT) / 22 (MCLK_DIV) / 256 - MCLK_MULT and MCLK_DIV defined in Output_i2s.cpp
    - in audiostream.h, and
    #define MCLK_MULT 1
    #define MCLK_DIV 22
    - in output_i2s.cpp

    I was pleasantly surprised that's the only thing you need to change in regards to FFT and I2SInputs at least, as the I2S clock is what's used to emulate the kHz speed, so everything else falls into place easily. I didn't check elsewhere, but if someone is not getting the proper kHz, I'm guessing a quick search for MCLK in the directory will show you other files it might be defined in.

  19. #19
    Junior Member
    Join Date
    Oct 2017
    Posts
    8
    Thank you, I tried it with 8 kHz sample rate and it works:
    audiostream.h:
    #elif F_CPU == 180000000
    #define MCLK_MULT 1 //16
    #define MCLK_DIV 87 // 255 // 180.000.000*16/2.048.000; 2.048.000/256=8kHz sample rate
    #define MCLK_SRC 0

    output_i2s.cpp:
    #ifndef AUDIO_SAMPLE_RATE_EXACT
    #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
    #define AUDIO_SAMPLE_RATE_EXACT 8081.89655 //44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256
    #elif defined(__MKL26Z64__)
    #define AUDIO_SAMPLE_RATE_EXACT 8081.89655 //22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256

  20. #20
    Member
    Join Date
    Nov 2014
    Location
    Italy
    Posts
    32
    Quote Originally Posted by schuchi View Post
    Thank you, I tried it with 8 kHz sample rate and it works:
    audiostream.h:
    #elif F_CPU == 180000000
    #define MCLK_MULT 1 //16
    #define MCLK_DIV 87 // 255 // 180.000.000*16/2.048.000; 2.048.000/256=8kHz sample rate
    #define MCLK_SRC 0

    output_i2s.cpp:
    #ifndef AUDIO_SAMPLE_RATE_EXACT
    #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
    #define AUDIO_SAMPLE_RATE_EXACT 8081.89655 //44117.64706 // 48 MHz / 1088, or 96 MHz * 2 / 17 / 256
    #elif defined(__MKL26Z64__)
    #define AUDIO_SAMPLE_RATE_EXACT 8081.89655 //22058.82353 // 48 MHz / 2176, or 96 MHz * 1 / 17 / 256
    I think you inverted the name of the file.

    Quote Originally Posted by Stein View Post
    Hi there, I'm working on a audio project as a part of a final B.S. project in mechatronics engineering and using a teensy as a test platform. Same as the OP I need better resolution per bin for FFT diagnosis, and was able to lower the kHz manually by changing :
    #define AUDIO_SAMPLE_RATE 17045.45454
    #define AUDIO_SAMPLE_RATE_EXACT 17045.45454 // 96 MHz * 1 (MCLK_MULT) / 22 (MCLK_DIV) / 256 - MCLK_MULT and MCLK_DIV defined in Output_i2s.cpp
    - in audiostream.h, and
    #define MCLK_MULT 1
    #define MCLK_DIV 22
    - in output_i2s.cpp


    I changed the files but the results is the semo, 43Hz of bin width

    How did you test the software?
    I use the fft example with a mic and produce a 430Hz freq, that results in the 11th bin...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •