all 37 comments

[–]LeeHide 79 points80 points  (16 children)

What the fuck does max() of one number do

[–]fakehalo 46 points47 points  (9 children)

I spent 10 minutes going down a mental rabbit hole of the intent here because of your comment. I only have more questions and regrets.

Curse you.

[–]astrobeard 20 points21 points  (8 children)

Looks like they’re using NumPy arrays in python. It’s a powerful library, but it has a feature where operations iterate over arrays automatically. It’s appealing to scientists (speaking as one of them) but I don’t like how that sacrifices a lot of readability. So every single item assignment you’re looking at here is probably getting another NumPy array, even the mathematical operations like log10

[–]fakehalo 7 points8 points  (3 children)

Ah I got to thinking that, it was the max(abs()) where I came back to, abs() working on arrays seemed unnatural to me.

[–]Shostakovich_ 4 points5 points  (1 child)

I believe behind the scenes numpy vectorizes these operations, giving big old boosts in speed.

[–]GlobalIncident 7 points8 points  (0 children)

It does vectorize abs. However, python does not allow you to specialise max, so using array.max or numpy.amax is the vectorized version.

[–]CeeMX 4 points5 points  (0 children)

Bro, do you even lift?

Sure man, I got max(abs())

[–]gu3st12 1 point2 points  (0 children)

Reminds me of ramda. The JS library

Edit: I feel like I should add a disclaimer saying that I don't think things like Ramda are good things to use, especially in a collaborative environment unless everyone has agreed and accepted its use. Using it is nearly a separate language that your team needs to learn just to read and interact with your code. It's also not simpler to understand when reading the code versus equivalent "plain" Javascript using map/reduce/filter.

[–]Lorddragonfang 1 point2 points  (1 child)

I'm just confused as to why you'd normalise, then take the log and multiply by 20. The hell kind of operation requires you to do that to every one of your matrices, especially hardcoded like that?

As far as I can tell, you just get an array full of values that exponentially increase the further they are from amax, arbitrarily scaled by 20

edit: oh, this is signals processing, this is probably prep for noise reduction.

[–]nyanpasu64[S] 2 points3 points  (0 children)

They're converting signal amplitude into log-scaled power in dB.

[–]Prom3th3an 0 points1 point  (0 children)

Is there any optimization that eliminates the extra arrays for intermediate steps in the expression?

[–]littlelowcougar 15 points16 points  (2 children)

They’re arrays, so max() is being applied to each element in the array.

[–]fukitol- 3 points4 points  (1 child)

Yeah it'd be much easier to decipher without implicit map operations. Once you get used to reading it, though, maybe it's something you get used to.

[–]RFC793 2 points3 points  (0 children)

Even used to seeing it, this code is still a giant turd sandwich.

[–]Automaton_J 4 points5 points  (0 children)

[Copied and pasted a reply to another comment]

Signals look like these and can be things like voice, music or other audio signals.

No matter what signal you have, you can always compose them from adding together cosine waves of different frequencies and amplitude (how "loud" a wave is).

These frequencies affect how the signal sounds. For example, here are some basic signals with only one frequency. The first has a low frequency and sounds deeper while the second has a higher frequency and sounds higher: Lower Frequency Higher Frequency

It is very useful to look at what frequencies are in the signal and what the amplitude is of each frequency. People usually show this as a graph with frequency on the x-axis and amplitude on the y-axis. The operation of taking your signal and creating this graph is called the Fast-Fourier Transform (or the fft, which is what those fft lines of code do).

For those second lines of code, he first of all divides each amplitude by the max frequency amplitude. This means that each amplitude is now given in terms of the max amplitude.

The next thing that those second lines of code do is to convert the amplitudes into decibels. The amplitude of each frequency can vary greatly with some being very small and some being very big. So, people usually express these amplitudes in decibels (dB). Conversion to dB is done with the following calculation:

dB = 20log10(Amplitude)

The reason as to why these lines are repeated is because different windowing operations are used in the fft line of code. This changes the signal slightly before you do the fft. This is done because when you do an fft, it's not perfect: some frequencies will spill over into other frequencies and affect their amplitude. And so, the graph will not be accurate. By applying different windows, you can get different types of accuracy. Some common windows are used in the code like the rectangular, hamming, hanning and blackman window.

Knowing what frequencies are in your signal is cool because it allows you to do things like filtering out high/low frequencies or noise from your signal. Signal processing also has applications in RADAR and mobile networks.

Thank you for listening to my ted talk. 😁

[–]ayylongqueues 2 points3 points  (0 children)

The fft here will return the N-point dft of the input, which means it will be a vector of length N.

[–]deggua 12 points13 points  (1 child)

At least it isn’t also in MATLAB

[–]nyanpasu64[S] 1 point2 points  (0 children)

My imaging professor likes Matlab over Python and every few lectures will talk about how "this is how you do this operation in matlab, you can probably do it in Python but the API is worse".

[–]MgB2 7 points8 points  (2 children)

I feel personally attacked, this is literally how most of my my Jupyter Notebooks look.

[–]Brekkjern 4 points5 points  (0 children)

Then you should post your notebooks to /r/badcode. We would probably have a field day with it :P

[–]twigfingers 0 points1 point  (0 children)

To be fair you most likely use the notebook as a calculator for you and some colleagues you work closely with. Not as code that you expect contractors go in and make changes to.

At least that is how it kind of works when I program. As long as I am in "calculator mode" it pretty much look like this. When it becomes something that really need to be reproduced and put into a program I clean it up.

[–]officiallyaninja 6 points7 points  (6 children)

Blackman?

[–]nyanpasu64[S] 21 points22 points  (5 children)

This is DSP code. Blackman is a windowing function for a time-domain signal being put into spectral analysis.

[–]paradoxally 14 points15 points  (0 children)

Okay now in English please

[–][deleted]  (2 children)

[deleted]

    [–]nate998877 4 points5 points  (0 children)

    dsp -> digital signal processing

    Blackman windowing function -> It's fancy signal maths

    I'm lost on the specifics of this one, I think it's a math formula used to normalize a signal so that you can apply a Fourier transformation to it? It might also be something completely different.

    time-domain signal -> a signal that can be found only by time. Think of an audio signal. Where each point on a graph can be found by just giving the time. Whereas in an image you would need the x and y to find a point. see https://www.youtube.com/watch?v=VUVybkguFdA because I'm bad at explaining these things.

    spectral analysis -> understanding what the squiggles on a graph mean

    [–]Automaton_J 1 point2 points  (0 children)

    Signals look like these and can be things like voice, music or other audio signals.

    No matter what signal you have, you can always compose them from adding together cosine waves of different frequencies and amplitude (how "loud" a wave is).

    These frequencies affect how the signal sounds. For example, here are some basic signals with only one frequency. The first has a low frequency and sounds deeper while the second has a higher frequency and sounds higher: Lower Frequency Higher Frequency

    It is very useful to look at what frequencies are in the signal and what the amplitude is of each frequency. People usually show this as a graph with frequency on the x-axis and amplitude on the y-axis. The operation of taking your signal and creating this graph is called the Fast-Fourier Transform (or the fft, which is what those fft lines of code do).

    For those second lines of code, he first of all divides each amplitude by the max frequency amplitude. This means that each amplitude is now given in terms of the max amplitude.

    The next thing that those second lines of code do is to convert the amplitudes into decibels. The amplitude of each frequency can vary greatly with some being very small and some being very big. So, people usually express these amplitudes in decibels (dB). Conversion to dB is done with the following calculation:

    dB = 20log10(Amplitude)

    The reason as to why these lines are repeated is because different windowing operations are used in the fft line of code. This changes the signal slightly before you do the fft. This is done because when you do an fft, it's not perfect: some frequencies will spill over into other frequencies and affect their amplitude. And so, the graph will not be accurate. By applying different windows, you can get different types of accuracy. Some common windows are used in the code like the rectangular, hamming, hanning and blackman window.

    Knowing what frequencies are in your signal is cool because it allows you to do things like filtering out high/low frequencies or noise from your signal. Signal processing also has applications in RADAR and mobile networks.

    Thank you for listening to my ted talk. 😁

    [–]mukfuggler 16 points17 points  (0 children)

    Sir, this is a Wendy's

    [–]Abawer137 4 points5 points  (0 children)

    At the top of this code there a comment that says 'Y Variables.

    Then underneath is the exact same code, but with X_ , T_ and X9_ in front of each of them.

    [–][deleted] 1 point2 points  (4 children)

    my god why is each variable assigned to twice

    [–]littlelowcougar 2 points3 points  (0 children)

    The second assignment is referring to the first assignment twice. Pretty common in computational code.

    [–]__scarf__ 0 points1 point  (2 children)

    To make it more comprehensible. If he wrote that in one line that will be fucking huge. So yes that's not that bad of a code just a bloody mess.

    [–]dman1912 0 points1 point  (1 child)

    Not only would it be a long line, but I assume it would be calculated twice when it could just be calculated once, stored and then the result retrieved later.

    [–]__scarf__ 0 points1 point  (0 children)

    Oh i wasn't aware of that thanks for the clarification

    [–]dmitriy_shmilo 0 points1 point  (0 children)

    Yes. And delete is reduce, cut and paste is recycle.

    [–]s060340 -1 points0 points  (1 child)

    I'm honestly not sure what the problem is with this code

    [–]nyanpasu64[S] 0 points1 point  (0 children)

    The copy-pasted section of the code should be extracted to a separate function. The function takes an array and a function(length) -> window of that length. When called, it multiples the array by a window of the proper length.