Module: DSP::Energy

Defined in:
lib/dsprb/energy.rb,
sig/dsprb.rbs

Constant Summary collapse

FLOOR =

Keeps the logarithm of a silent frame finite, placing digital silence near -120 dB.

Returns:

  • (::Float)
1e-12

Class Method Summary collapse

Class Method Details

.envelope_db(samples, window:, hop:) ⇒ ::Array[::Float]

Parameters:

  • (samples)
  • window: (::Integer)
  • hop: (::Integer)

Returns:

  • (::Array[::Float])

Raises:

  • (ArgumentError)


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/dsprb/energy.rb', line 36

def envelope_db(samples, window:, hop:)
  raise ArgumentError, "window must be positive, got #{window}" unless window.positive?
  raise ArgumentError, "hop must be positive, got #{hop}" unless hop.positive?
  return [] if samples.length < window

  running = 0.0
  index = 0
  while index < window
    running += samples[index] * samples[index]
    index += 1
  end

  out = [to_db(running / window)]
  position = hop
  while position + window <= samples.length
    running = slide(samples, running, position, hop, window)
    out << to_db([running, 0.0].max / window)
    position += hop
  end

  out
end

.frame_db(frame) ⇒ ::Float

Parameters:

  • (frame)

Returns:

  • (::Float)

Raises:

  • (ArgumentError)


10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/dsprb/energy.rb', line 10

def frame_db(frame)
  raise ArgumentError, "frame must not be empty" if frame.empty?

  total = 0.0
  index = 0
  while index < frame.length
    total += frame[index] * frame[index]
    index += 1
  end

  to_db(total / frame.length)
end

.slide(samples, running, position, hop, window) ⇒ ::Float

Parameters:

  • (samples)
  • (::Float)
  • (::Integer)
  • (::Integer)
  • (::Integer)

Returns:

  • (::Float)


59
60
61
62
63
64
65
66
67
68
# File 'lib/dsprb/energy.rb', line 59

def slide(samples, running, position, hop, window)
  index = position - hop
  while index < position
    running -= samples[index] * samples[index]
    running += samples[index + window] * samples[index + window]
    index += 1
  end

  running
end

.to_db(power) ⇒ ::Float

Parameters:

  • (::Float)

Returns:

  • (::Float)


70
# File 'lib/dsprb/energy.rb', line 70

def to_db(power) = 10.0 * Math.log10(power + FLOOR)

.zero_crossing_rate(frame) ⇒ ::Float

Parameters:

  • (frame)

Returns:

  • (::Float)


23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/dsprb/energy.rb', line 23

def zero_crossing_rate(frame)
  return 0.0 if frame.length < 2

  crossings = 0
  index = 1
  while index < frame.length
    crossings += 1 if frame[index].negative? != frame[index - 1].negative?
    index += 1
  end

  crossings.to_f / (frame.length - 1)
end