Discussion:
[praat-users] Question: F0 and formants (what about subharmonics?)
ivangarcianisa@yahoo.com [praat-users]
2017-01-31 22:43:37 UTC
Permalink
Hi everyone, I am new in acoustic analysis and I am trying to measure the F0 contour and formants of a non-human primate vocalization. I've read about subharmonics and that some algorithms used by acoustic analysis softwares may measure subharmonics as the fundamental frequency. Does anybody know how can I detect subharmonics with Praat to make an accurate measure of the fundamental frequency?


Thank you.



Ivan.
Xavier St-Gelais xavier.st-gelais1@uqac.ca [praat-users]
2017-02-02 14:54:25 UTC
Permalink
Hi,


I am sorry for asking this question since it seems like it's been asked recently (https://uk.groups.yahoo.com/neo/groups/praat-users/conversations/messages/7972), but unfortunately, it has received no answer and I have run into the same problem.


I am currently working in bioacoustics. Commonly reported measurements are the "frequency quartiles" (at 25, 50 and 75%): for example, 1st frequency quartile is the frequency (in Hz) at which the average spectrum (over the duration of a whole vocalization of varying duration) can be divided into two frequency intervals containing 25% and 75% of the vocalization's total energy.


Now, these measurements can be obtained by other programs, but I would like to centralize all my measurements in Praat to integrate them in a bigger script. As far as I know, there is no built-in way to obtain these frequencies in Praat.


What I've tried to do, starting from a Sound object representing the vocalization, is this:


- Create a FFT Spectrum
- List the values of the Spectrum object (using the "List" command), retrieving only the frequencies and the energy density
- Load the values into a Table
- Append a column for the cumulative energy
- Apply a formula to fill in the cumulative energy values


- Retrieve the total energy from the last row
- Multiply it by 0.25, 0.5 and 0.75 to obtain the energy tresholds to be found
- Search the table for the frequencies for which the cumulative energy is nearest the calculated tresholds


Now, apart from the fact that this process is extremely slow, it also gives very strange results. For example, for a very "standard" vocalization with a F0 at around 2200 Hz and at least 3 harmonics that are clearly visible, I obtain these quartiles:


25% 2083 Hz
50% 2099 Hz
75% 2190 Hz


These do not look right at all from a visual inspection of the spectrum, and do not correspond to the values given by (for example) the "seewave" package in R (they range from approx. 2100 Hz to 4450 Hz in that program, which also seems more in line with the literature).


Do you happen to know of a relatively fast and reliable way to get these measurements using Praat? Should I maybe use something else than a Spectrum object?


Best regards and, once more, sorry for asking this question again, even though it came from another user last time,


Xavier St-Gelais
Canada
Paul Boersma paul.boersma@uva.nl [praat-users]
2017-02-03 08:48:39 UTC
Permalink
Post by Xavier St-Gelais xavier.st-***@uqac.ca [praat-users]
- Create a FFT Spectrum
- List the values of the Spectrum object (using the "List" command), retrieving only the frequencies and the energy density


Now, apart from the fact that this process is extremely slow, it also gives very strange results.
Yes. Because the energy density is listed in dB, not in Pascal^2. You skipped the necessary conversion step.
_____

Paul Boersma
Professor of Phonetic Sciences
University of Amsterdam
Spuistraat 134, room 632
1012VB Amsterdam, The Netherlands
http://www.fon.hum.uva.nl/paul/
Xavier St-Gelais xavier.st-gelais1@uqac.ca [praat-users]
2017-02-03 09:23:05 UTC
Permalink
Dear Paul,


Thank you for your answer. I am sorry if this may come off as a poorly thought-out question, but I may be confused with the units: when looking at the Table obtained with the List command from the Spectrum object (with the columns asked being "Frequency" and "Energy density"), the second column is called "energy(pa^2/hz^2)". Now, those are all values above 0, as I thought would be expected for energy levels.


Unfortunately, I have no background in calculus; what conversion should I apply to these values? I thought I had avoided the dB problem by getting the "energy density" and not the "power density".


Thanks in advance and best regards,


Xavier St-Gelais
________________________________________
De : Paul Boersma [***@uva.nl]
Envoyé : vendredi 3 février 2017 03:48
À : Xavier St-Gelais
Cc : praat-***@yahoogroups.co.uk
Objet : Re: [praat-users] Frequency quartiles in Praat (from a spectrum)
Post by Xavier St-Gelais xavier.st-***@uqac.ca [praat-users]
- Create a FFT Spectrum
- List the values of the Spectrum object (using the "List" command), retrieving only the frequencies and the energy density


Now, apart from the fact that this process is extremely slow, it also gives very strange results.
Yes. Because the energy density is listed in dB, not in Pascal^2. You skipped the necessary conversion step.
_____


Paul Boersma
Professor of Phonetic Sciences
University of Amsterdam
Spuistraat 134, room 632
1012VB Amsterdam, The Netherlands
http://www.fon.hum.uva.nl/paul/
Paul Boersma paul.boersma@uva.nl [praat-users]
2017-02-03 10:11:56 UTC
Permalink
Post by Xavier St-Gelais xavier.st-***@uqac.ca [praat-users]
when looking at the Table obtained with the List command from the Spectrum object (with the columns asked being "Frequency" and "Energy density"), the second column is called "energy(pa^2/hz^2)". Now, those are all values above 0, as I thought would be expected for energy levels.
You are right. I was looking at the power density column.

Your procedure looked correct, then. Perhaps there is a mistake in one of the formulas. Could you provide the script that you used? Then we can have a look.
_____

Paul Boersma
Professor of Phonetic Sciences
University of Amsterdam
Spuistraat 134, room 632
1012VB Amsterdam, The Netherlands
http://www.fon.hum.uva.nl/paul/
Xavier St-Gelais xavier.st-gelais1@uqac.ca [praat-users]
2017-02-03 10:36:39 UTC
Permalink
Certainly. Here is the script (to launch with the Spectrum object selected):


################################
#Get to x$ a table containing 1st column: frequencies and 2nd column: energy
#This chunk is ugly, but I do not know of a faster way to go from the result of "List" to a Table object
x$ = List: "no", "yes", "no", "no", "yes", "no"
x$ > test.txt
Read from file: "test.txt"
deleteFile: "test.txt"


#Append a cumulative energy column and fill in the blanks (knowing that the 2nd row contains the energy in pa^2/hz^2)

Append column: "cumul"
Formula: "cumul", "if row=1 then self[col-1] else self[row-1,col]+self[col-1] fi"


#Loop that runs 3 times, 1 for each quartile
for i from 1 to 3
quantile = i*0.25


#Retrieve total energy (cumulative energy at last row)
n = Get number of rows
sum = Get value: n, "cumul"

#Cumulative energy to be found
treshold = sum*quantile


#Ugly test to go through the table faster:
#split it into 2, save the previous higher
#bracket, and search to find the range
#which should contain the desired cumulative
#energy value

currLowBracket = n div 2
prevHighBracket = n
ok = 1


while ok
test = Get value: currLowBracket, "cumul"
#if test value is still over treshold,
#it means we have to lower the high bracket
if test > treshold
prevHighBracket = currLowBracket
currLowBracket = currLowBracket div 2
#if not, we've found the right range to look in
else
ok = 0
endif
endwhile


#When range is found, go through subsection
#of the Table to find value

#As soon as test is over treshold, we have
#found our row
foundRow = currLowBracket
while test < treshold
test = Get value: foundRow, "cumul"
foundRow = foundRow + 1
endwhile


frequencyOfQuartile = Get value: foundRow, "freq(Hz)"
appendInfoLine: quantile, " = ", round(frequencyOfQuartile), " Hz"
endfor


appendInfoLine: "END OF SCRIPT"
################################


Now, this script is not particularly optimized, that's for sure. But it gives out values that could be real. We've actually checked with Matlab and though there is a small displacement between values (Matlab gives them around 20 to 30 Hz lower each), there is an agreement. What seems to be the problem really is the "seewave" package for R, which gives very different values. I may have been wrong to use it as a reference, or may have misused its parameters.


As a side note, if there is a quicker way to execute this procedure (without going with a Table object, maybe, but I don't know how that would be done), I would be very interested. For the longest sound we have to measure (i.e. the most detailed spectrum), it takes about 4 seconds to give results, given the table's dimensions.


Moreover, I know it is not particulary precise to retrieve the frequency of the row in which the treshold has been passed rather than to try a kind of "interpolation", but I do not know how I would go about that.


Thanks again for your time,


Xavier St-Gelais

Loading...