2

I'm new here and unfortunately I have really no knowledge at all about digital signal processing so my apologies if this is rather a stupid question or a duplicate. I have some audio signal which consists of beep tones. I need to figure out how many beep tones it consists of.

I have the following signal: enter image description here

But if you look closely you'll see that the "beeps" look like this: enter image description here

After adding an Envelope filter the signal looks like this: enter image description here

Is there a way to produce an array like this from the last signal?

[0,1,0,1,0,1,0,1,0,1,0,1,0] 

That represents the amount of "beeps". Can someone help me out on how to do this properly?

lennon310
  • 3,590
  • 19
  • 24
  • 27
John
  • 121
  • 2
  • 2
    I think the envelope detection was the hardest part. From there, you just set a threshold between the high and the low, and everything below becomes a 1, everything above a 0. – Marcus Müller Aug 22 '22 at 08:33
  • by the way, I'm biased towards GNU Radio, but the official GNU Radio tutorials show you how to do such operations on audio coming from a recording or an audio device input, and do a bit more (you'll even be able to find things like preambles etc., if necessary even writing very short programs to take over signal processing steps). – Marcus Müller Aug 22 '22 at 08:41
  • I've managed to find the peaks, thanks for the support btw. @MarcusMüller can you maybe recommend something to learn the basic about dsp. Just the basiscs that at least I know a bit about audio signals and so on. I have see this: http://www.dspguide.com/pdfbook.htm but not sure if this is a rookie approach or not – John Aug 22 '22 at 09:34
  • I don't know what kind of rookie you are, if you're a scientist or an engineer, then a book titled "the scientist's and engineer's…" might be right. A friend of mine runs pysdr.org, which is more radio-signal oriented. The GNU Radio wiki (link see above) has a "suggested reading" page. And: I got a used second edition Oppenheim&Schafer "discrete-time signal processing" for two handful of dollars through a used book market website. – Marcus Müller Aug 22 '22 at 09:43
  • I'm a computer programmer, one that never got a course on dsp. But indeed there are resources enough. Even for free on the internet. Thanks for your time! – John Aug 22 '22 at 09:54
  • John, this question and the answers might give you some other reference pointers. – Peter K. Aug 22 '22 at 13:18
  • just go through the signal from left to right and when it goes up a lot that's the start of a beep and when it goes down a lot that's the end of a beep? – user253751 Aug 23 '22 at 20:16
  • You could possibly use an energy detector to do the job. What you could use is a binary hypothesis testing method on the energy of the signals, which boils down to picking the appropriate threshold for the energy of the signal (there's good mathematical justification behind that of course, I am just simplifying the concept here). Since you have the original signal, you could calculate the "instantaneous energy" (or the RMS value) and pick a threshold by visual inspection. You can find some information here: https://ieeexplore.ieee.org/document/1028251. – ZaellixA Sep 18 '23 at 18:04

4 Answers4

0
  1. Import the signal into MATLAB

  2. Try J.Hussain's Amplitude Shift Keying (ASK) Modulation and Demodulation

lennon310
  • 3,590
  • 19
  • 24
  • 27
  • 1
    John Bofarull, although your suggestions may work quite well to lead to a solution of the question asked here, I strongly encourage you to at least provide a brief explanation of the proposed solution. This way, the person asked the question could right away start working on it and it will act as a reference point for other people that may have the same (or similar) problem in the future. – ZaellixA Aug 25 '22 at 12:59
0

It's relatively straightforward to do using librosa:

If your beeps are a known signal, then correlating the beep with the signal and picking peaks works reasonably well:

        audio, fs = librosa.load(file, mono=True)
        beep, _ = librosa.load('beep.wav', sr=fs)
    clicks = []
    correlation = signal.correlate(audio, beep, mode='valid', method='fft')
    correlation /= np.max(np.abs(correlation), axis=0)
    peaks = librosa.util.peak_pick(correlation,
                                   pre_max=512,
                                   post_max=512,
                                   pre_avg=512,
                                   post_avg=512,
                                   delta=0.5,
                                   wait=2048)
    ticks = librosa.samples_to_time(peaks, sr=fs)

    for t in ticks:
        print(f'beep {t:0.3f}')

If your beep isn't a known signal then librosa's note onset detection is an alternative - it's less accurate than the correlation approach but works reasonably well on a signal with clearly defined transitions. If the beeps are at regular intervals then you can use beat tracking:

        audio, fs = librosa.load(file, mono=True)
        onset_env = librosa.onset.onset_strength(y=audio, sr=fs, aggregate=np.median)
        tempo, frames = librosa.beat.beat_track(onset_envelope=onset_env, sr=fs)
        beats = librosa.frames_to_time(frames, sr=fs)
    for beat in beats:
        print(f'beat @ {beat:0.3f}')

If the beeps aren't at regular intervals then use the note onsets:

        audio, fs = librosa.load(file, mono=True)
        onset_env = librosa.onset.onset_strength(y=audio, sr=fs, aggregate=np.median)
        frames = librosa.onset.onset_detect(onset_envelope=onset_env, sr=fs)
        onsets = librosa.frames_to_time(frames, sr=fs)
    for onset in onsets:
        print(f'note onset @ {onset:0.3f}')

```

tonys
  • 101
  • 1
  • 1
0

The act of converting a continuous univariate signal of activation into a discrete set of events is a common sub-problem in Sound Event Detection.

The simplest approach is to select a threshold, and then binarize the sequence with that. Then count the runs of true value as one contiguous event region.

You may want to avoid small gaps in the events, or require that the events are of minimum size, or that they are at least a certain distance apart. This can be done by post processing the binarized signal with morphological operators. A simple version of this is known as hang-over.

Another strategy would be to binarize using hysteresis, using two sets of thresholds. This avoids disruptions when the activations hover around the threshold.

Another way of cleaning up the signal is to apply a Hidden Markov Model.

Jon Nordby
  • 267
  • 1
  • 9
0

I would suggest the following:

  • find the lowest frequency (fl) in your signal. Its period will define a window length (wl)
  • reshape your signal to be N rows and WL columns
  • sum horizontally
  • if sum is above threshold you will have signal
  • from the sum vector build a new signal
  • expand it by repeating each value WL times

An example with matlab:

% after finding lowest frequency (FL) with FFT
WL = 1/FL;
N = length(s) \ WL;
total_n = WL*N;
% Calculate the number of zeros to pad
num_zeros_to_pad = max(0, total_elements_required - numel(signal));

% Pad zeros to the signal padded_signal = padarray(signal, [0, num_zeros_to_pad], 0, 'post');

% Reshape the padded signal reshaped_signal = reshape(padded_signal, N, WL);

win_sum = sum(reshaped_signal) bins = win_sum>threshold

% Expand each element expanded_signal = kron(bins, ones(1, WL));

Filipe Pinto
  • 721
  • 4
  • 11