Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4856

Beginners • Raspberry Pico, MAX7819, Micropython based Spectrum Visualizer

$
0
0
Hello! I'm trying to build a spectrum visualizer for frequencies ranging 20-20000 Hz. I'm aware commercial products exist, but I'm doing it for the learning experience.

Each column of the MAX7819 module will correspond to a frequency: 30, 60, 125, 250, 375, 500, 750, 1000, 1500, 2000, 3000, 4000, 6000, 8000, 12000, 16000, 20000.

For testing purposes I'm feeding the Pico with a pure sine wave of 1000 Hz and amplitude of 2.5v.

The expected results would be a big magnitude value for 1000 Hz and an Intensity value of 8 (8 rows of the 1000 Hz LED column lit), while the other magnitude values are zero and corresponding Intensity values also 0.

Unfortunately I can't understand why the FFT is throwing garbage values, specially for frequencies from 30 to 1500 hz. The peak that I should be seeing at 1000 Hz is nonexistent (a little peak do appear at 5000 Hz tough)

Already ruled out electrical noise, so probably is a problem with my code implementation. Inspecting other projects or using IA threw me even more off course.

Any help will be even appreciated (even if it involves throwing the whole code away and re-think the project from scratch.

Code:

from machine import ADC, Pin, SPIimport timeimport mathimport arrayimport max7219# SPI setup for the LED matrix displayspi = SPI(0, baudrate=115200, polarity=0, phase=0, sck=Pin(18), mosi=Pin(19))cs = Pin(15, Pin.OUT)  # Chip Select for SPI# Initialize the displaynum_matrices = 4matrix = max7219.Matrix8x8(spi, cs, num_matrices)# Clear the displaymatrix.fill(0)matrix.show()# Configure the analog pin (let's use ADC0 which is GP26 on the Pico)# Input audio signal from 20 to 20.000 hz, 2.50v# Coupled with a 10uF capacitoradc = ADC(Pin(26))# Desired sampling rate (samples per second)sampling_rate = 48000  # 48 kHz# Calculate the delay between samples (in microseconds)sample_interval_us = int(1e6 / sampling_rate)  # Convert to microseconds# Function to sample the audio signaldef sample_audio(samples=128):    audio_samples = array.array('H')  # Use array for memory efficiency    for _ in range(samples):        audio_samples.append(adc.read_u16())  # Read the analog value (0-65535)        time.sleep_us(sample_interval_us)  # Delay between samples    return audio_samples# Apply Hamming window to the samplesdef apply_window(samples):    windowed_samples = []    for i in range(len(samples)):        windowed_samples.append(samples[i] * (0.54 - 0.46 * math.cos(2 * math.pi * i / (len(samples) - 1))))    return windowed_samples# Perform FFTdef fft(samples):    N = len(samples)    levels = int(math.log2(N))    # Bit-reversal permutation    def bit_reverse(n, bits):        reversed = 0        for _ in range(bits):            reversed = (reversed << 1) | (n & 1)            n >>= 1        return reversed    indices = [bit_reverse(i, levels) for i in range(N)]    sorted_samples = [samples[i] for i in indices]    # Cooley-Tukey FFT    m = 2    while m <= N:        omega_m = math.e ** (-2j * math.pi / m)        for k in range(0, N, m):            omega = 1            for j in range(m // 2):                t = omega * sorted_samples[k + j + m // 2]                u = sorted_samples[k + j]                sorted_samples[k + j] = u + t                sorted_samples[k + j + m // 2] = u - t                omega *= omega_m        m *= 2    return sorted_samples# Function to get the intensity at specific frequenciesdef get_intensity_at_frequencies(fft_result, frequencies, sample_rate, num_samples):    columnIndex = 1    intensity_list = []    for freq in frequencies:        index = int(freq * num_samples / sample_rate)        if index < len(fft_result):            magnitude = abs(fft_result[index])            print(f"freq: {freq} mag: {magnitude}")            intensity_list.append((columnIndex, freq, magnitude))        else:            intensity_list.append((columnIndex, freq, -1))        columnIndex += 1    return intensity_list# Normalize intensity to range 0 to 8def normalize_intensity(intensity_list, max_intensity=2318515, max_value=8):    if max_intensity == 0:        return [(freq, 0) for _, freq, _ in intensity_list]  # Avoid division by zero    normalized_intensity = []    for columnIndex, freq, magnitude in intensity_list:        normalized_magnitude = int((magnitude / max_intensity) * max_value)        normalized_intensity.append((columnIndex, freq, normalized_magnitude))    return normalized_intensity# Frequencies to inspectfrequencies = [30, 60, 125, 250, 375, 500, 750, 1000, 1500, 2000, 3000, 4000, 6000, 8000, 12000, 16000, 20000]# Function to display intensities on the LED matricesdef display_intensities(intensity_list):    matrix.fill(0)  # Clear the display    for columnIndex, freq, value in intensity_list:        print(f"Column: {columnIndex}, Frequency: {freq}, Intensity: {value}")        for row in range(value):            matrix.pixel(columnIndex, 7 - row, 1)  # Turn on the LED    matrix.show()# Main loopwhile True:    audio_samples = sample_audio()    windowed_samples = apply_window(audio_samples)    fft_result = fft(windowed_samples)    intensity = get_intensity_at_frequencies(fft_result, frequencies, sampling_rate, len(windowed_samples))    normalized_intensity = normalize_intensity(intensity)    display_intensities(normalized_intensity)    #time.sleep(0.1)
freq: 30 mag: 410849.0
freq: 60 mag: 410849.0
freq: 125 mag: 410849.0
freq: 250 mag: 410849.0
freq: 375 mag: 177652.7
freq: 500 mag: 177652.7
freq: 750 mag: 1593.784
freq: 1000 mag: 1593.784
freq: 1500 mag: 905.7179
freq: 2000 mag: 1962.383
freq: 3000 mag: 2820.535
freq: 4000 mag: 702.5089
freq: 6000 mag: 767.7787
freq: 8000 mag: 1147.657
freq: 12000 mag: 1375.547
freq: 16000 mag: 1416.093
freq: 20000 mag: 1114.418

Column: 1, Frequency: 30, Intensity: 1
Column: 2, Frequency: 60, Intensity: 1
Column: 3, Frequency: 125, Intensity: 1
Column: 4, Frequency: 250, Intensity: 1
Column: 5, Frequency: 375, Intensity: 0
Column: 6, Frequency: 500, Intensity: 0
Column: 7, Frequency: 750, Intensity: 0
Column: 8, Frequency: 1000, Intensity: 0
Column: 9, Frequency: 1500, Intensity: 0
Column: 10, Frequency: 2000, Intensity: 0
Column: 11, Frequency: 3000, Intensity: 0
Column: 12, Frequency: 4000, Intensity: 0
Column: 13, Frequency: 6000, Intensity: 0
Column: 14, Frequency: 8000, Intensity: 0
Column: 15, Frequency: 12000, Intensity: 0
Column: 16, Frequency: 16000, Intensity: 0
Column: 17, Frequency: 20000, Intensity: 0

Statistics: Posted by menticol — Tue Jun 04, 2024 2:18 am — Replies 0 — Views 5



Viewing all articles
Browse latest Browse all 4856

Trending Articles