Acoustics and audition#

[3]

LING 497 Phonetic Analysis: Articulation, Acoustics, Audition

The Pennsylvania State University

Prof. Deborah Morton


Revised

25 May 2023


Vowel Spectrograms#


Formant Data#

Observations#

Hide code cell source
import numpy  as np
import pandas as pd

obs = pd.DataFrame(
  data=[
    ['hæd','æ',772.2623598361888 ,1731.6866205977226],
    ['hɛd','ɛ',574.208631287283  ,1918.637682685363 ],
    ['hid','i',305.92339403193955,2458.4996663060283],
    ['hɪd','ɪ',453.5730951234637 ,2072.92348845572  ],
    ['hɑd','ɑ',714.6610521359538 ,1214.4713341175295],
    ['hʊd','ʊ',476.80292121316353,1338.2178121189354],
    ['hʌd','ʌ',618.9116494455797 ,1425.8562296798175],
    ['hud','u',318.0286268276335 ,1095.993125792178 ],
    ['hɔd','ɔ',610.8859754665131 ,935.5714048615686 ],
    ['bæt','æ',812.4152837356295 ,1702.1079409783133],
    ['bɛd','ɛ',534.3448157343192 ,1891.7585442888867],
    ['bid','i',289.82041231188634,2429.2999144902774],
    ['bɪd','ɪ',450.1635653561586 ,2009.4880143110365],
    ['bɑd','ɑ',708.1091727260111 ,1189.9926250011079],
    ['bʊk','ʊ',497.65304819673605,1020.9113547201716],
    ['bʌd','ʌ',606.6914116015801 ,1372.059084614637 ],
    ['bud','u',323.43445114657317,1264.2416721859588],
    ['bɔt','ɔ',636.7402932330717 ,994.824262278683  ],
  ],
  columns=[
  'word',
  'vowel',
  'F1_Hz',
  'F2_Hz',
  ],
)
obs.drop(columns=['word'])   \
  .set_index(keys=['vowel']) \
  .to_csv('lab3_obs.csv')
obs.round(2)
Error in parse(text = x, srcfile = src): <text>:1:8: unexpected symbol
1: import numpy
           ^
Traceback:

Averages [Hz, acoustic frequency]#

Hide code cell source
avg = obs.drop(columns=['word']) \
  .groupby(by=['vowel'])         \
  .mean()                        \
  .round(2)
avg.to_csv('lab3_avg.csv')
avg
F1_Hz F2_Hz
vowel
i 297.87 2443.90
u 320.73 1180.12
æ 792.34 1716.90
ɑ 711.39 1202.23
ɔ 623.81 965.20
ɛ 554.28 1905.20
ɪ 451.87 2041.21
ʊ 487.23 1179.56
ʌ 612.80 1398.96

Averages [barks, auditory frequency]#

\( \begin{aligned} \text{bark}=6\sinh^{-1}\left(\frac{f}{600}\right) \end{aligned} \)

Hide code cell source
def freq_to_bark (freq : float) -> float:
  bark = 6*np.arcsinh(freq/600)
  return bark

avg['F1_bark'] = avg['F1_Hz'].apply(freq_to_bark)
avg['F2_bark'] = avg['F2_Hz'].apply(freq_to_bark)
avg.drop(columns=['F1_Hz','F2_Hz']).to_csv('lab3_bark.csv')
avg.drop(columns=['F1_Hz','F2_Hz'])
F1_bark F2_bark
vowel
i 2.868206 12.673842
u 3.071393 8.572313
æ 6.545572 10.642287
ɑ 6.040524 8.671778
ɔ 5.454945 7.521406
ɛ 4.958718 11.234881
ɪ 4.173832 11.630689
ʊ 4.452301 8.569775
ʌ 5.378270 9.496836

Plotting the data using R#

.libPaths()
'/Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library'
Hide code cell source
packages <- c(
  'ggplot2',
  'readr',
  'dplyr',
  'tidyverse',
  'scales',
  'repr',
  'phonR',
  'vowels',
  'magrittr'
)

# Install packages not yet installed
installed_packages <- packages %in% rownames(installed.packages())
if (any(installed_packages == FALSE)) {
  install.packages(packages[!installed_packages])
}

# Load packages
invisible(lapply(packages, library, character.only = TRUE))
Attaching package: ‘dplyr’


The following objects are masked from ‘package:stats’:

    filter, lag


The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union


── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
 tibble  3.1.7      stringr 1.4.0
 tidyr   1.2.0      forcats 0.5.1
 purrr   0.3.4     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
 dplyr::filter() masks stats::filter()
 dplyr::lag()    masks stats::lag()

Attaching package: ‘scales’


The following object is masked from ‘package:purrr’:

    discard


The following object is masked from ‘package:readr’:

    col_factor



Attaching package: ‘magrittr’


The following object is masked from ‘package:purrr’:

    set_names


The following object is masked from ‘package:tidyr’:

    extract

Observations [Hz]#

obs <- read.csv('lab3_obs.csv')
obs
A data.frame: 18 × 3
vowelF1_HzF2_Hz
<chr><dbl><dbl>
æ772.26241731.6866
ɛ574.20861918.6377
i305.92342458.4997
ɪ453.57312072.9235
ɑ714.66111214.4713
ʊ476.80291338.2178
ʌ618.91161425.8562
u318.02861095.9931
ɔ610.8860 935.5714
æ812.41531702.1079
ɛ534.34481891.7585
i289.82042429.2999
ɪ450.16362009.4880
ɑ708.10921189.9926
ʊ497.65301020.9114
ʌ606.69141372.0591
u323.43451264.2417
ɔ636.7403 994.8243
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(obs, aes(x=F2_Hz, y=F1_Hz, label=vowel, color=vowel)) +
  geom_text(size=10) +
  scale_x_reverse(
      position='bottom',
      breaks=seq(0, 3000, 200)) +
  scale_y_reverse(
      position='left',
      breaks=seq(0, 1000, 100)) +
  labs(
    x='F2 [Hz]\n',
    y='F1 [Hz]\n',
    title='Observed F1 vs F2') +
  theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=20)
  )

suppressWarnings(print(plt))
../../../../_images/64f998c64e7ec4f64983295e29006343dd191581ffb3604241caf5663f95c7a5.png

Averages [Hz]#

avg <- read.csv('lab3_avg.csv')
avg
A data.frame: 9 × 3
vowelF1_HzF2_Hz
<chr><dbl><dbl>
i297.872443.90
u320.731180.12
æ792.341716.90
ɑ711.391202.23
ɔ623.81 965.20
ɛ554.281905.20
ɪ451.872041.21
ʊ487.231179.56
ʌ612.801398.96
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(avg, aes(x=F2_Hz, y=F1_Hz, label=vowel, color=vowel)) +
  geom_text(size=10) +
  scale_x_reverse(
      position='bottom',
      breaks=seq(0, 3000, 200)) +
  scale_y_reverse(
      position='left',
      breaks=seq(0, 1000, 100)) +
  labs(
    x='F2 [Hz]\n',
    y='F1 [Hz]\n',
    title='Averaged F1 vs F2') +
  theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=20)
  )

suppressWarnings(print(plt))
../../../../_images/9135a8b001215b15bba8c3d1105621451b2abd2f104377c9292596e79c6b5e68.png

Averages [barks]#

barks <- read.csv('lab3_bark.csv')
barks
A data.frame: 9 × 3
vowelF1_barkF2_bark
<chr><dbl><dbl>
i2.86820612.673842
u3.071393 8.572313
æ6.54557210.642287
ɑ6.040524 8.671778
ɔ5.454945 7.521406
ɛ4.95871811.234881
ɪ4.17383211.630689
ʊ4.452301 8.569775
ʌ5.378270 9.496836
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(barks, aes(x=F2_bark, y=F1_bark, label=vowel, color=vowel)) +
  geom_text(size=10) +
  scale_x_reverse(
      position='bottom') +
  scale_y_reverse(
      position='left') +
  labs(
    x='F2 [barks]\n',
    y='F1 [barks]\n',
    title='Averaged F1 vs F2') +
  theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=20)
  )

suppressWarnings(print(plt))
../../../../_images/91913c55cf123a2edc02a7d30c04f95e213e7557c3fbac5b30a6c57817f5bda4.png

Hz vs Barks#


Simulating a larger data set#

set.seed(10)
vowels = data.frame(
       vowel = rep(c('a', 'e', 'i', 'o', 'u'), each=50),
       F1 = c(rnorm(50, mean=800, sd=100),
              rnorm(50, mean=600, sd=100),
              rnorm(50, mean=350, sd=100),
              rnorm(50, mean=600, sd=100),
              rnorm(50, mean=350, sd=100)),
       F2 = c(rnorm(50, mean=1500, sd=150),
              rnorm(50, mean=2000, sd=150),
              rnorm(50, mean=2500, sd=150),
              rnorm(50, mean=1000, sd=150),
              rnorm(50, mean=800, sd=150))
)
vowels
A data.frame: 250 × 3
vowelF1F2
<chr><dbl><dbl>
a801.87461661.684
a781.57471639.767
a662.86691280.881
a740.08321364.089
a829.45451397.948
a838.97941659.475
a679.19241396.138
a763.63241329.956
a637.33271335.808
a774.35221348.064
a910.17801561.542
a875.57821571.661
a776.17661150.518
a898.74451502.438
a874.13901647.053
a808.93471620.952
a704.50561517.940
a780.48501134.508
a892.55211504.653
a848.29791449.638
a740.36891460.434
a581.47131446.622
a732.51341427.827
a588.09391533.410
a673.48021864.487
a762.63381724.445
a731.24451392.419
a712.78411429.942
a789.82391599.439
a774.62191845.027
u317.0775719.0060
u321.7178511.1535
u393.2429951.1747
u319.2393758.1148
u344.3364612.5651
u423.3515987.2737
u359.7312771.1680
u513.0892936.7964
u406.0611476.2595
u482.9565993.4416
u322.1177735.7835
u223.3268761.7496
u325.0852999.0737
u351.7988925.8035
u387.7073580.2499
u429.6009707.5621
u265.9323815.9159
u129.4528523.3975
u237.1944557.5366
u215.8690834.1515
u510.5114938.1825
u424.4424750.3195
u436.2082993.0851
u389.5156808.5891
u400.9119469.4100
u337.7450721.5634
u359.2585962.1178
u314.2120763.5288
u314.0345663.5830
u452.8571669.7551
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(data=vowels, aes(x=F2, y=F1, color=vowel, label=vowel))+
geom_text(size=8)+
coord_cartesian(
    xlim=c(3000, 200),
    ylim=c(1000, 100))+
theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=18))
plt
../../../../_images/6de8c9e26ac0e49ba99aa5b81d847237d666db6c5233aec4eb24c903e2aa6e37.png
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(data=vowels, aes(x=F2, y=F1, color=vowel, label=vowel))+
geom_text(size=8)+
scale_x_reverse(
    position='bottom',
    breaks=seq(200, 3000, 500))+
scale_y_reverse(
    position='left',
    breaks=seq(100, 1000, 250))+
labs(
    x='F2 [Hz]\n',
    y='F1 [Hz]\n',
    title='Density')+
geom_density_2d(alpha=0.3)+
coord_cartesian(
    xlim=c(3000, 200),
    ylim=c(1000, 100))+
theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=18))
plt
../../../../_images/f0e26f095f6f616fbf581591cfeb35f587e2d26241c74ba3ebcc4c604771c39a.png
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(data=vowels, aes(x=F2, y=F1, color=vowel, label=vowel))+
geom_text(size=8)+
scale_x_reverse(
    position='bottom',
    breaks=seq(200, 3000, 500))+
scale_y_reverse(
    position='left',
    breaks=seq(100, 1000, 250))+
labs(
    x='F2 [Hz]\n',
    y='F1 [Hz]\n',
    title='')+
stat_ellipse(type='norm', alpha=0.3)+
coord_cartesian(
    xlim=c(3000, 200),
    ylim=c(1000, 100))+
theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=18))
plt
../../../../_images/48d7a350418ecf59e97beba393601caba6d9572dfca2414b392f78d83e22a94a.png
means <- vowels %>% group_by(vowel) %>% summarize(meanF1=mean(F1),
                                                  meanF2=mean(F2),
                                                  seF1=sd(F1)/sqrt(n()),
                                                  seF2=sd(F2)/sqrt(n()))
means
A tibble: 5 × 5
vowelmeanF1meanF2seF1seF2
<chr><dbl><dbl><dbl><dbl>
a765.87051506.940012.2528521.84624
e606.81982042.937113.8109720.84642
i352.40422516.714513.7474623.33361
o578.60331008.828813.6018923.78942
u351.1237 776.037613.0469924.21912
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(data=means, aes(x=meanF2, y=meanF1, color=vowel, label=vowel))+
geom_errorbar(aes(ymin=meanF1-seF1, ymax=meanF1+seF1), width=0)+
geom_errorbarh(aes(xmin=meanF2-seF2, xmax=meanF2+seF2), height=0)+
geom_text(position=position_nudge(x=50, y=50), size=8)+
scale_x_reverse(
    position='bottom',
    breaks=seq(200, 3000, 500))+
scale_y_reverse(
    position='left',
    breaks=seq(100, 1000, 250))+
labs(
    x='F2 [Hz]\n',
    y='F1 [Hz]\n',
    title='')+
coord_cartesian(
    xlim=c(3000, 200),
    ylim=c(1000, 100))+
theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=18))
plt
../../../../_images/f1fba64f278e8025f887eccfc61e4874c4835caad28100c98742f5ade405c631.png
Hide code cell source
options(repr.plot.width=10, repr.plot.height=10)

plt <- ggplot(data=means, aes(x=meanF2, y=meanF1, color=vowel, label=vowel))+
geom_text(size=8)+
scale_x_reverse(
    position='bottom',
    breaks=seq(200, 3000, 500))+
scale_y_reverse(
    position='left',
    breaks=seq(100, 1000, 250))+
labs(
    x='F2 [Hz]\n',
    y='F1 [Hz]\n',
    title='')+
stat_ellipse(data=vowels, aes(x=F2, y=F1), type='norm')+
coord_cartesian(
    xlim=c(3000, 200),
    ylim=c(1000, 100))+
theme(
    legend.position='none',
    plot.title=element_text(hjust=0.5),
    text=element_text(size=18))
plt
../../../../_images/d9c360a536d8b83827521eea9476bc219d00626ba9a52ab22d24a5e7a48f5a35.png