DiscreteFourierTransform.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import numpy as np
  2. from matplotlib import pyplot as plt
  3. SAMPLE_RATE = 44100 # Гц
  4. DURATION = 5 # Секунды
  5. def generate_sine_wave(freq, sample_rate, duration):
  6. x = np.linspace(0, duration, sample_rate*duration, endpoint=False)
  7. frequencies = x * freq
  8. # 2pi для преобразования в радианы
  9. y = np.sin((2 * np.pi) * frequencies)
  10. return x, y
  11. # Генерируем волну с частотой 2 Гц, которая длится 5 секунд
  12. # x, y = generate_sine_wave(2, SAMPLE_RATE, DURATION)
  13. # plt.plot(x, y)
  14. # plt.show()
  15. '''
  16. Микширование аудиосигналов состоит всего из двух этапов:
  17. cложение сигналов;
  18. нормализация результата.
  19. '''
  20. _, nice_tone = generate_sine_wave(400, SAMPLE_RATE, DURATION)
  21. _, noise_tone = generate_sine_wave(4000, SAMPLE_RATE, DURATION)
  22. noise_tone = noise_tone * 0.3
  23. mixed_tone = nice_tone + noise_tone
  24. '''
  25. Символ подчеркивания (_) мы используем, чтобы отбросить значения x,
  26. возвращаемые функцией generate_sine_wave() – нам не нужно складывать значения времени.
  27. Следующий шаг – нормализация, масштабирование сигнала под целевой формат.
  28. В нашем случае это 16-битное целое число в диапазоне от -32768 до 32767:
  29. '''
  30. normalized_tone = np.int16((mixed_tone / mixed_tone.max()) * 32767)
  31. #plt.plot(normalized_tone[:1000])
  32. #plt.show() # Видимая нами синусоидальная волна – это сгенерированный тон 400 Гц, искаженный тоном 4000 Гц.
  33. from scipy.io.wavfile import write
  34. #write("mysinewave.wav", SAMPLE_RATE, normalized_tone)
  35. '''
  36. Используем быстрое преобразование Фурье для удаления шума
  37. Быстрое преобразование Фурье (FFT) – алгоритм, который позволяет вычислить частотный спектр сигнала:
  38. '''
  39. from scipy.fft import fft, fftfreq
  40. # число точек в normalized_tone
  41. N = SAMPLE_RATE * DURATION
  42. # вычисление преобразования Фурье:
  43. yf = fft(normalized_tone) # вычисляет само преобразование
  44. xf = fftfreq(N, 1/SAMPLE_RATE) # находит частоты в центре каждого «бина» на выходе fft()
  45. # Под бином здесь понимается интервал значений, сгруппированных аналогично гистограмме.
  46. # plt.plot(xf, np.abs(yf))
  47. # plt.show() # Пики положительных частот находятся на позициях 400 и 4000 Гц.
  48. """
  49. Примечание
  50. Кстати, по графику можно заметить, что fft() возвращает в качестве максимальной частоты чуть
  51. более 20 тысяч герц, а именно: 22050 Гц. Это значение составляет ровно половину частоты
  52. дискретизации и называется частотой Найквиста. Действительно, из фундаментальной теоремы
  53. обработки сигналов (теорема Котельникова), следует, что частота дискретизации должна как
  54. минимум вдвое превышать максимальную частоту сигнала.
  55. """
  56. # Обрабатываем сигнал еще быстрее с помощью rfft()
  57. from scipy.fft import rfft, rfftfreq
  58. # обратите внимание на r в начале имён функций
  59. yf = rfft(normalized_tone)
  60. xf = rfftfreq(N, 1/SAMPLE_RATE)
  61. # plt.plot(xf, np.abs(yf))
  62. # plt.show()
  63. # Фильтрация сигнала
  64. '''
  65. Самая замечательная вещь в преобразовании Фурье заключается в том, что оно обратимо.
  66. Любой сигнал, измененный в частотной области, можно преобразовать обратно во временную
  67. область. Воспользуемся этим, чтобы отфильтровать высокочастотный шум.
  68. Возвращаемые rfft() значения соответствуют мощности каждого частотного бина.
  69. Если мы установим мощность бина равной нулю, соответствующая частота перестанет
  70. присутствовать в результирующем сигнале во временной области:
  71. '''
  72. # Максимальная частота составляет половину частоты дискретизации
  73. points_per_freq = len(xf) / (SAMPLE_RATE / 2)
  74. # Наша целевая частота - 4000 Гц
  75. target_idx = int(points_per_freq * 4000)
  76. #Обнулим yf для индексов около целевой частоты:
  77. yf[target_idx-2:target_idx+2] = 0
  78. # plt.plot(xf, np.abs(yf))
  79. # plt.show()
  80. # Применение обратного преобразования Фурье
  81. from scipy.fft import irfft
  82. new_sig = irfft(yf)
  83. # plt.plot(new_sig[:1000])
  84. # plt.show()
  85. norm_new_sig = np.int16(new_sig * (32767 / new_sig.max()))
  86. write("clean.wav", SAMPLE_RATE, norm_new_sig)