DecibelsChallenge_PersonalData

DecibelsChallenge_PersonalData

For the third Decibels Challenge, the prompt for data is personal data. I decided to use data from 10 workouts I did and use SonicPi to sonify the process and Python to clean it up.

Wanted the sounds to represent the various stages a heart goes through in a workout. This explains some of the chaotic tension/feelings that can be heard in this track

Sounds

IllestPreacha · Decibels 2023 March Challenge ; Personal Data : Heart Edition

Data

Table

HR_AVG

HR_MAX

HR_MIN

Calories

CardioLoad

Zone3

Zone2

HR_Max-MIn

Zone2+3

Other Zones

CaloLoad

0

147

174

98

554

71

0.44

0.1

76

0.54

0.46

7.802816901

1

123

156

108

876

80

0.36

0.37

48

0.73

0.27

10.95

2

110

135

74

44

3

0.16

0.61

61

0.77

0.23

14.66666667

3

100

126

80

224

16

0

0.12

46

0.12

0.88

14

4

130

156

74

292

29

0.56

0.38

82

0.94

0.06

10.06896552

5

116

140

95

137

11

0.05

0.72

45

0.77

0.23

12.45454545

6

126

158

93

434

42

0.34

0.49

65

0.83

0.17

10.33333333

7

123

154

86

593

58

0.44

0.31

68

0.75

0.25

10.22413793

8

136

136

85

570

69

0.24

0.17

51

0.41

0.59

8.260869565

9

90

123

73

157

12

0

0.15

50

0.15

0.85

13.08333333

10

138

172

108

497

57

0.64

0.16

64

0.8

0.2

8.719298246

Column Names

  • HR_AVG - Average Heart Rate

  • HR_Max - Max Heart Rate

  • HR_Min - Min Heart Rate

  • Calories - Calories Burnt

  • CardioLoad - the cardio intensity given for that workout

  • Zone2, Zone3, Other Zones - Refer to the Five Heart zones

  • CaloLoad - Is the ratio of Calories Burnt: Cardio Load

These columns are used in the SonicPi Code to make the sounds and can be used to understand which columns are affecting which part

Code

SonicPi Code

Comments in Code for more information

require 'csv'

#naming the Dataset DipInCode and going to read the file
Heart = CSV.parse(File.read("C:/Creatuve Code Challenges/Sonification Challenges/March 2023/HeartRatePrep.csv"), headers: true)


i = 0


live_loop :HeartZone do

  #these effects are going to be affected by the zones, since they are between 0 and 1, which is the range for the mix function
  with_fx :echo, mix: Heart[i]['Other Zones'].to_f  do
    with_fx :ixi_techno, mix: Heart[i]['Zone3'].to_f do
      with_fx :krush, mix: Heart[i]['Zone2+3'].to_f do

        #a trio of synths to add more musicality/variance to the listening experience
        use_synth [:organ_tonewheel,:mod_sine,:mod_sine].choose

        #Corresponds to the note being played
        play Heart[i]['HR_MIN'].to_f, decay: Heart[i]['Other Zones'].to_f, amp: dice(12)
        #We can even pass a list of times which it will treat as a circle of times:
        play_pattern_timed chord(Heart[i]['HR_MIN'].to_f, :m13), [Heart[i]['Zone2+3'].to_f, Heart[i]['Other Zones'].to_f ,Heart[i]['HR_MAX'].to_f/ Heart[i]['HR_MIN'].to_f]
      end
    end
  end

  i += 1 #counter

  if i == Heart.length #make the loop nonstop
    i = 0
  end

  #spacing
  sleep Math.sin(Heart[i]['HR_MAX'].to_f/ Heart[i]['HR_MIN'].to_f)
end


live_loop :HeartBeat do

#same as the previous loop, with the difference being a random choosing of 3 effects instead of 3 synths in this portion 

  with_fx :flanger, depth: Heart[i]['Other Zones'].to_f  do
    with_fx :echo,  mix: Heart[i]['Zone2+3'].to_f do
      with_fx [:ping_pong,:vowel,:whammy].choose, mix: Heart[i]['Other Zones'].to_f do
        sample :ambi_piano,beat_stretch: Heart[i]['Zone2'].to_f ,pitch: Heart[i]['CaloLoad'].to_f
        sample :perc_impact1,beat_stretch: Math.cos(Heart[i]['Other Zones'].to_f), decay: Heart[i]['CaloLoad'].to_f
      end
    end
  end

  i += 1

  if i == Heart.length #make the loop nonstop
    i = 0
  end

  sleep Heart[i]['HR_MAX'].to_f/ Heart[i]['HR_MIN'].to_f
end

Python Code

import pandas as pd
df = pd.read_csv('Jan16_23_heart - Sheet1.csv')
df.info()

<class 'pandas.core.frame.DataFrame'> RangeIndex: 11 entries, 0 to 10 Data columns (total 7 columns): # Column Non-Null Count Dtype
--- ------ -------------- -----
0 HR_AVG 11 non-null int64
1 HR_MAX 11 non-null int64
2 HR_MIN 11 non-null int64
3 Calories 11 non-null int64
4 CardioLoad 11 non-null int64
5 Zone3 11 non-null float64 6 Zone2 11 non-null float64 dtypes: float64(2), int64(5) memory usage: 744.0 bytes

df. describe()
HR_AVGHR_MAXHR_MINCaloriesCardioLoadZone3Zone2
count11.00000011.00000011.00000011.00000011.00000011.00000011.000000
mean121.727273148.18181888.545455398.00000040.7272730.2936360.325455
std16.87063117.32523112.902431249.91118427.7564080.2220030.210778
min90.000000123.00000073.00000044.0000003.0000000.0000000.100000
25%113.000000135.50000077.000000190.50000014.0000000.1050000.155000
50%123.000000154.00000086.000000434.00000042.0000000.3400000.310000
75%133.000000157.00000096.500000562.00000063.5000000.4400000.435000
max147.000000174.000000108.000000876.00000080.0000000.6400000.720000
#time to make new columns based on the information provided and get more Numbers for the sonification


#HeartRate Max-MIn , getting the difference between Heart Rates
df['HR_Max-MIn'] = df['HR_MAX']- df['HR_MIN'] 

#Total percentage of HeartRatein Zone3 + Zone2
df['Zone2+3'] = df['Zone2'] + df['Zone3'] 

#Total percentage of Other Heart Zones
df['Other Zones'] = 1 - df['Zone2'] - df['Zone3'] 

#Calories divided by Cardio Load
df['CaloLoad'] = df['Calories'] / df['CardioLoad']
df
HR_AVGHR_MAXHR_MINCaloriesCardioLoadZone3Zone2HR_Max-MInZone2+3Other ZonesCaloLoad
014717498554710.440.10760.540.467.802817
1123156108876800.360.37480.730.2710.950000
2110135744430.160.61610.770.2314.666667
310012680224160.000.12460.120.8814.000000
413015674292290.560.38820.940.0610.068966
511614095137110.050.72450.770.2312.454545
612615893434420.340.49650.830.1710.333333
712315486593580.440.31680.750.2510.224138
813613685570690.240.17510.410.598.260870
99012373157120.000.15500.150.8513.083333
10138172108497570.640.16640.800.208.719298
df.to_csv('HeartRatePrep.csv')