ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • llama3.1 on Jetson Orin Nano Super FFT Demo 1, 2, 3
    카테고리 없음 2025. 2. 8. 00:37

    USER

    fast fourier transformation (FFT)에 대해 이해하고 싶습니다. 진폭과 주파수가 다른 sine과 cosine 웨이브들을 각각 5개씩 더한 입력 데이터를 만들고, 이 데이터를 FFT하여 결과에서 입력한 진폭과 주파수를 확인하는 파이썬 예제를 부탁합니다.

    ASSISTANT

    FFT는 시간 도메인에서의 신호의 분석을 주파수 도메인으로 변환해주는 중요한 알고리즘입니다.

    아래 예제에서는 파이썬의 numpy 라이브러리를 이용하여 FFT를 수행하고, 결과에서 입력한 진폭과 주파수를 확인합니다.

    import numpy as np
    
    # 진폭 1,2,3,4,5 각 주파수 0.1,0.2,0.3,0.4,0.5에 해당하는 sine 웨이브
    t = np.linspace(0, 1, 1000) # 시간 도메인에서 1000개의 데이터를 생성
    
    data1 = 5 * np.sin(2 * np.pi * 0.1 * t)
    data2 = 3 * np.sin(2 * np.pi * 0.2 * t)
    data3 = 2 * np.sin(2 * np.pi * 0.3 * t)
    data4 = 4 * np.sin(2 * np.pi * 0.4 * t)
    data5 = 1 * np.sin(2 * np.pi * 0.5 * t)
    
    # 진폭 6,7,8,9,10 각 주파수 0.1,0.2,0.3,0.4,0.5에 해당하는 cosine 웨이브
    data6 = 6 * np.cos(2 * np.pi * 0.1 * t)
    data7 = 7 * np.cos(2 * np.pi * 0.2 * t)
    data8 = 8 * np.cos(2 * np.pi * 0.3 * t)
    data9 = 9 * np.cos(2 * np.pi * 0.4 * t)
    data10 = 10 * np.cos(2 * np.pi * 0.5 * t)
    
    # 입력 데이터
    data = data1 + data2 + data3 + data4 + data5 + data6 + data7 + data8 + data9 + data10
    
    # FFT를 수행하고, 결과를 주파수 도메인에서 확인합니다.
    fft_data = np.fft.fft(data)
    freq = np.fft.fftfreq(len(t), d=t[1]-t[0])
    
    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(12,6))
    plt.subplot(2, 1, 1)
    plt.plot(t, data)
    plt.title('시간 도메인')
    plt.xlabel('Time (s)')
    plt.ylabel('Amplitude')
    
    plt.subplot(2, 1, 2)
    plt.plot(freq, np.abs(fft_data))
    plt.title('주파수 도메인')
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Magnitude')
    
    plt.tight_layout()
    plt.show()
    
    # FFT를 수행하고 결과에서 진폭과 주파수를 확인합니다.
    index_max = np.argmax(np.abs(fft_data))
    
    freq_max = freq[index_max]
    amp_max = np.abs(fft_data[index_max])
    
    print(f"주파수: {freq_max}")
    print(f"진폭: {amp_max}")
    
    # 각 주파수의 진폭을 계산합니다.
    for i in range(len(freq)):
        if abs(freq[i] - 0.1) < 0.01 or abs(freq[i] - 0.2) < 0.01 or abs(freq[i] - 0.3) < 0.01 \
           or abs(freq[i] - 0.4) < 0.01 or abs(freq[i] - 0.5) < 0.01:
            amp = np.abs(fft_data[i])
            if freq[i] == 0.1:
                print(f"진폭(주파수=0.1Hz): {amp}")
            elif freq[i] == 0.2:
                print(f"진폭(주파수=0.2Hz): {amp}")
            elif freq[i] == 0.3:
                print(f"진폭(주파수=0.3Hz): {amp}")
            elif freq[i] == 0.4:
                print(f"진폭(주파수=0.4Hz): {amp}")
            elif freq[i] == 0.5:
                print(f"진폭(주파수=0.5Hz): {amp}")
    
    for i in range(len(freq)):
        if abs(freq[i]) < 0.01 and np.abs(np.angle(fft_data[i])) > 3.14/2 and np.abs(np.angle(fft_data[i])) < 3.14*3/2:
            amp = np.abs(fft_data[i])
            print(f"진폭(주파수=0Hz): {amp}")

    이 예제에서, np.fft.fftfreq 함수를 사용하여 FFT의 주파수를 계산하고, np.fft.fft 함수를 사용하여 FFT를 수행합니다.

    출력된 주파수 도메인 결과에서, 각 주파수의 진폭을 계산하는 코드를 추가했습니다. 이 코드는 주파수가 0.1, 0.2, 0.3, 0.4, 0.5 Hz 인 곳을 탐색하고, 해당 주파수의 진폭을 출력합니다.

    주의: FFT의 결과에서, 주파수 도메인의 실제값은 주기적으로 반복되기 때문에, 주파수가 0.1Hz인 경우를 탐색할 때는 주파수가 0.1Hz 인 곳을 찾아야 합니다.

    실행 결과

    주파수: 0.0
    진폭: 25119.570388396238

    USER

    주파수에 비해 데이터의 시간 구간이 너무 짧은 것 아닙니까? 0.1Hz의 주기가 10초인데 데이터는 1초 밖에 안 됩니다.

    ASSISTANT

    FFT를 사용할 때, 데이터의 시간 구간이 주파수의 주기보다 길어야 합니다.

    현재 예제에서는 주파수 0.1Hz의 경우, 주기는 10초가지만 데이터는 1초밖에 안 되기 때문에 FFT의 결과에서 진폭을 올바르게 계산할 수 없습니다.

    데이터의 시간 구간을 주파수의 주기와 비슷하게 만들면 아래와 같습니다:

    import numpy as np
    
    # 진폭 1,2,3,4,5 각 주파수 0.1,0.2,0.3,0.4,0.5에 해당하는 sine 웨이브
    t = np.linspace(0, 10, 1000) # 시간 도메인에서 1000개의 데이터를 생성
    
    data1 = 5 * np.sin(2 * np.pi * 0.1 * t)
    data2 = 3 * np.sin(2 * np.pi * 0.2 * t)
    data3 = 2 * np.sin(2 * np.pi * 0.3 * t)
    data4 = 4 * np.sin(2 * np.pi * 0.4 * t)
    data5 = 1 * np.sin(2 * np.pi * 0.5 * t)
    
    # 진폭 6,7,8,9,10 각 주파수 0.1,0.2,0.3,0.4,0.5에 해당하는 cosine 웨이브
    data6 = 6 * np.cos(2 * np.pi * 0.1 * t)
    data7 = 7 * np.cos(2 * np.pi * 0.2 * t)
    data8 = 8 * np.cos(2 * np.pi * 0.3 * t)
    data9 = 9 * np.cos(2 * np.pi * 0.4 * t)
    data10 = 10 * np.cos(2 * np.pi * 0.5 * t)
    
    # 입력 데이터
    data = data1 + data2 + data3 + data4 + data5 + data6 + data7 + data8 + data9 + data10
    
    # FFT를 수행하고, 결과를 주파수 도메인에서 확인합니다.
    fft_data = np.fft.fft(data)
    freq = np.fft.fftfreq(len(t), d=t[1]-t[0])
    
    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(12,6))
    plt.subplot(2, 1, 1)
    plt.plot(t, data)
    plt.title('시간 도메인')
    plt.xlabel('Time (s)')
    plt.ylabel('Amplitude')
    
    plt.subplot(2, 1, 2)
    plt.plot(freq, np.abs(fft_data))
    plt.title('주파수 도메인')
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Magnitude')
    
    plt.tight_layout()
    plt.show()
    
    # FFT를 수행하고 결과에서 진폭과 주파수를 확인합니다.
    index_max = np.argmax(np.abs(fft_data))
    
    freq_max = freq[index_max]
    amp_max = np.abs(fft_data[index_max])
    
    print(f"주파수: {freq_max}")
    print(f"진폭: {amp_max}")
    
    # 각 주파수의 진폭을 계산합니다.
    for i in range(len(freq)):
        if abs(freq[i] - 0.1) < 0.01 or abs(freq[i] - 0.2) < 0.01 or abs(freq[i] - 0.3) < 0.01 \
           or abs(freq[i] - 0.4) < 0.01 or abs(freq[i] - 0.5) < 0.01:
            amp = np.abs(fft_data[i])
            if freq[i] == 0.1:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            elif freq[i] == 0.2:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            elif freq[i] == 0.3:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            elif freq[i] == 0.4:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            else:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")

    이제 데이터의 시간 구간은 주파수의 주기와 비슷하게 만들었습니다. FFT를 사용할 때, 데이터의 시간 구간이 주파수의 주기보다 길어야 합니다.

    실행 결과

    주파수: 0.4995
    진폭: 5003.80719808941
    진폭(주파수: 0.0999 Hz): 3937.566186639917
    진폭(주파수: 0.1998 Hz): 3843.3946304382303
    진폭(주파수: 0.2997 Hz): 4154.287443000267
    진폭(주파수: 0.3996 Hz): 4937.456320748701
    진폭(주파수: 0.4995 Hz): 5003.80719808941

    USER

    그래프 확대 이동하며 보기 좋게 matplotlib 대신 plotly를 이용하여 그래프를 그려주세요.

    ASSISTANT

    matplotlib 대신 plotly를 사용하여 그래프를 그려 보겠습니다.

    import numpy as np
    import plotly.express as px
    import plotly.graph_objects as go
    
    # 진폭 1,2,3,4,5 각 주파수 0.1,0.2,0.3,0.4,0.5에 해당하는 sine 웨이브
    t = np.linspace(0, 10, 1000) # 시간 도메인에서 1000개의 데이터를 생성
    
    data1 = 5 * np.sin(2 * np.pi * 0.1 * t)
    data2 = 3 * np.sin(2 * np.pi * 0.2 * t)
    data3 = 2 * np.sin(2 * np.pi * 0.3 * t)
    data4 = 4 * np.sin(2 * np.pi * 0.4 * t)
    data5 = 1 * np.sin(2 * np.pi * 0.5 * t)
    
    # 진폭 6,7,8,9,10 각 주파수 0.1,0.2,0.3,0.4,0.5에 해당하는 cosine 웨이브
    data6 = 6 * np.cos(2 * np.pi * 0.1 * t)
    data7 = 7 * np.cos(2 * np.pi * 0.2 * t)
    data8 = 8 * np.cos(2 * np.pi * 0.3 * t)
    data9 = 9 * np.cos(2 * np.pi * 0.4 * t)
    data10 = 10 * np.cos(2 * np.pi * 0.5 * t)
    
    # 입력 데이터
    data = data1 + data2 + data3 + data4 + data5 + data6 + data7 + data8 + data9 + data10
    
    # FFT를 수행하고, 결과를 주파수 도메인에서 확인합니다.
    fft_data = np.fft.fft(data)
    freq = np.fft.fftfreq(len(t), d=t[1]-t[0])
    
    fig = go.Figure()
    fig.add_trace(go.Scatter(x=t, y=data, name='시간 도메인'))
    fig.update_layout(title='시간 도메인',
                      xaxis_title='Time (s)',
                      yaxis_title='Amplitude')
    
    # 주파수 도메인의 그래프
    index_max = np.argmax(np.abs(fft_data))
    freq_max = freq[index_max]
    amp_max = np.abs(fft_data[index_max])
    
    fig2 = go.Figure()
    fig2.add_trace(go.Scatter(x=freq, y=np.abs(fft_data), name='주파수 도메인'))
    fig2.update_layout(title='주파수 도메인',
                      xaxis_title='Frequency (Hz)',
                      yaxis_title='Magnitude')
    
    # 각 주파수의 진폭을 계산합니다.
    for i in range(len(freq)):
        if abs(freq[i] - 0.1) < 0.01 or abs(freq[i] - 0.2) < 0.01 or abs(freq[i] - 0.3) < 0.01 \
           or abs(freq[i] - 0.4) < 0.01 or abs(freq[i] - 0.5) < 0.01:
            amp = np.abs(fft_data[i])
            if freq[i] == 0.1:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            elif freq[i] == 0.2:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            elif freq[i] == 0.3:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            elif freq[i] == 0.4:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
            else:
                print(f"진폭(주파수: {freq[i]} Hz): {amp}")
    
    fig.show()
    fig2.show()
    
    # 각 주파수의 진폭을 그래프로 표시합니다.
    for i in range(len(freq)):
        if abs(freq[i] - 0.1) < 0.01 or abs(freq[i] - 0.2) < 0.01 or abs(freq[i] - 0.3) < 0.01 \
           or abs(freq[i] - 0.4) < 0.01 or abs(freq[i] - 0.5) < 0.01:
            amp = np.abs(fft_data[i])
            if freq[i] == 0.1:
                fig3 = go.Figure()
                fig3.add_trace(go.Scatter(x=t, y=data1, name='sin(2π*0.1t)'))
                fig3.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Time (s)',
                                  yaxis_title='Amplitude')
                fig3.show()
            elif freq[i] == 0.2:
                fig4 = go.Figure()
                fig4.add_trace(go.Scatter(x=t, y=data2, name='sin(2π*0.2t)'))
                fig4.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Time (s)',
                                  yaxis_title='Amplitude')
                fig4.show()
            elif freq[i] == 0.3:
                fig5 = go.Figure()
                fig5.add_trace(go.Scatter(x=t, y=data3, name='sin(2π*0.3t)'))
                fig5.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Time (s)',
                                  yaxis_title='Amplitude')
                fig5.show()
            elif freq[i] == 0.4:
                fig6 = go.Figure()
                fig6.add_trace(go.Scatter(x=t, y=data4, name='sin(2π*0.4t)'))
                fig6.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Time (s)',
                                  yaxis_title='Amplitude')
                fig6.show()
            else:
                fig7 = go.Figure()
                fig7.add_trace(go.Scatter(x=t, y=data5, name='sin(2π*0.5t)'))
                fig7.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Time (s)',
                                  yaxis_title='Amplitude')
                fig7.show()
    
            if freq[i] == 0.1:
                fig8 = go.Figure()
                fig8.add_trace(go.Scatter(x=freq, y=fft_data[:len(freq)], name='sin(2π*0.1t)'))
                fig8.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Frequency (Hz)',
                                  yaxis_title='Magnitude')
                fig8.show()
            elif freq[i] == 0.2:
                fig9 = go.Figure()
                fig9.add_trace(go.Scatter(x=freq, y=fft_data[:len(freq)], name='sin(2π*0.2t)'))
                fig9.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Frequency (Hz)',
                                  yaxis_title='Magnitude')
                fig9.show()
            elif freq[i] == 0.3:
                fig10 = go.Figure()
                fig10.add_trace(go.Scatter(x=freq, y=fft_data[:len(freq)], name='sin(2π*0.3t)'))
                fig10.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Frequency (Hz)',
                                  yaxis_title='Magnitude')
                fig10.show()
            elif freq[i] == 0.4:
                fig11 = go.Figure()
                fig11.add_trace(go.Scatter(x=freq, y=fft_data[:len(freq)], name='sin(2π*0.4t)'))
                fig11.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Frequency (Hz)',
                                  yaxis_title='Magnitude')
                fig11.show()
            else:
                fig12 = go.Figure()
                fig12.add_trace(go.Scatter(x=freq, y=fft_data[:len(freq)], name='sin(2π*0.5t)'))
                fig12.update_layout(title=f'주파수: {freq[i]} Hz',
                                  xaxis_title='Frequency (Hz)',
                                  yaxis_title='Magnitude')
                fig12.show()

    이 코드는 주파수가 0.1, 0.2, 0.3, 0.4, 0.5인 경우에만 그래프를 그립니다.

    실행 결과