add signal generator sin and more...
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
#include <sndfile.h>
|
||||
#include <hack/logger/logger.hpp>
|
||||
|
||||
#include "utils/var.hpp" // IWYU pragma: keep
|
||||
#include "utils/var.hpp" // IWYU pragma: keep
|
||||
#include "utils/signal_generator/signal_generator.hpp" // IWYU pragma: keep
|
||||
#include "utils/using.hpp"
|
||||
#include "utils/workers/setup.hpp"
|
||||
#include "utils/workers/result.hpp"
|
||||
|
||||
@@ -12,6 +12,7 @@ headers = [
|
||||
'utils/workers/result.hpp',
|
||||
'utils/workers/setup.hpp',
|
||||
'utils/windows/hann/hann.hpp',
|
||||
'utils/signal_generator/signal_generator.hpp',
|
||||
|
||||
# plugins
|
||||
'plugins/magnitude/magnitude.hpp',
|
||||
@@ -25,6 +26,7 @@ sources = [
|
||||
'utils/fvec/fvec.cpp',
|
||||
|
||||
'utils/windows/hann/hann.cpp',
|
||||
'utils/signal_generator/signal_generator.cpp',
|
||||
|
||||
# plugins
|
||||
'plugins/magnitude/magnitude.cpp',
|
||||
|
||||
219
src/utils/signal_generator/signal_generator.cpp
Normal file
219
src/utils/signal_generator/signal_generator.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "signal_generator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace hr
|
||||
{
|
||||
std::vector<float> signal_generator::generate(SIGNAL_TYPE type, NOISE noise)
|
||||
{
|
||||
std::vector<float> res;
|
||||
switch (type)
|
||||
{
|
||||
case SIGNAL_TYPE::SIN:
|
||||
res = sin(noise);
|
||||
break;
|
||||
case SIGNAL_TYPE::SQUARE:
|
||||
res = square(noise);
|
||||
break;
|
||||
case SIGNAL_TYPE::TRIANGLE:
|
||||
res = triangle(noise);
|
||||
break;
|
||||
case SIGNAL_TYPE::SAW:
|
||||
res = saw(noise);
|
||||
break;
|
||||
case SIGNAL_TYPE::SPEECH_LIKE:
|
||||
res = speech_like(noise);
|
||||
break;
|
||||
case SIGNAL_TYPE::NOISE_ONLY:
|
||||
res = noise_only();
|
||||
break;
|
||||
case SIGNAL_TYPE::THREE_SINES:
|
||||
res = three_sines(noise);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::sin(NOISE noise)
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
{
|
||||
float t = i * 0.02f;
|
||||
signal[i] = m_params.m_amplitude * std::sin(m_params.m_frequency * t * 2 * M_PI);
|
||||
}
|
||||
|
||||
if (noise == NOISE::YES)
|
||||
{
|
||||
// создаем распределение случайных величин
|
||||
std::uniform_real_distribution<> dist(-m_params.m_noise_level, m_params.m_noise_level);
|
||||
for (auto& s : signal) s += dist(m_gen);
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::square(NOISE noise)
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
{
|
||||
float t = i * 0.02f;
|
||||
float phase = m_params.m_frequency * t * 2 * M_PI;
|
||||
// Прямоугольный сигнал: +1 когда sin > 0, -1 когда sin < 0
|
||||
signal[i] = m_params.m_amplitude * (std::sin(phase) > 0 ? 1.0f : -1.0f);
|
||||
}
|
||||
|
||||
if (noise == NOISE::YES)
|
||||
{
|
||||
std::uniform_real_distribution<> dist(-m_params.m_noise_level, m_params.m_noise_level);
|
||||
for (auto& s : signal) s += dist(m_gen);
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::triangle(NOISE noise)
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
{
|
||||
float t = i * 0.02f;
|
||||
float phase = fmod(m_params.m_frequency * t, 1.0f); // 0..1
|
||||
|
||||
// Треугольный сигнал: линейный рост от -1 до 1, потом падение
|
||||
if (phase < 0.25f) signal[i] = m_params.m_amplitude * (4.0f * phase); // 0..1
|
||||
else if (phase < 0.75f) signal[i] = m_params.m_amplitude * (2.0f - 4.0f * phase); // 1..-1
|
||||
else signal[i] = m_params.m_amplitude * (4.0f * phase - 4.0f); // -1..0
|
||||
}
|
||||
|
||||
if (noise == NOISE::YES)
|
||||
{
|
||||
std::uniform_real_distribution<> dist(-m_params.m_noise_level, m_params.m_noise_level);
|
||||
for (auto& s : signal) s += dist(m_gen);
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::saw(NOISE noise)
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
{
|
||||
float t = i * 0.02f;
|
||||
float phase = fmod(m_params.m_frequency * t, 1.0f); // 0..1
|
||||
|
||||
// Пилообразный сигнал: линейный рост от -1 до 1, потом резкий сброс
|
||||
signal[i] = m_params.m_amplitude * (2.0f * phase - 1.0f); // -1..1
|
||||
}
|
||||
|
||||
if (noise == NOISE::YES)
|
||||
{
|
||||
std::uniform_real_distribution<> dist(-m_params.m_noise_level, m_params.m_noise_level);
|
||||
for (auto& s : signal) s += dist(m_gen);
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::noise_only()
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
std::uniform_real_distribution<> dist(-m_params.m_amplitude, m_params.m_amplitude);
|
||||
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
signal[i] = dist(m_gen);
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::speech_like(NOISE noise)
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
|
||||
// Базовая частота (основной тон речи)
|
||||
float base_freq = m_params.m_frequency;
|
||||
|
||||
// Добавляем гармоники, как в реальной речи
|
||||
float harmonics[] = { 2.0f, 3.0f, 4.0f, 5.0f }; // гармоники
|
||||
float harmonics_amp[] = { 0.7f, 0.5f, 0.3f, 0.2f }; // их амплитуды
|
||||
|
||||
// Форманты (резонансные частоты речи)
|
||||
float formants[] = {500.0f, 1500.0f, 2500.0f, 3500.0f};
|
||||
float formants_amp[] = {0.4f, 0.6f, 0.3f, 0.2f};
|
||||
|
||||
// Модуляция амплитуды (как при произношении слогов)
|
||||
float envelope_freq = 2.0f; // частота слогов
|
||||
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
{
|
||||
float t = i * 0.02f;
|
||||
float value = 0.0f;
|
||||
|
||||
// Основной тон + гармоники
|
||||
for (int h = 0; h < 4; h++)
|
||||
value += harmonics_amp[h] * std::sin(2 * M_PI * base_freq * harmonics[h] * t);
|
||||
|
||||
// Форманты (резонансы)
|
||||
for (int f = 0; f < 4; f++)
|
||||
value += formants_amp[f] * std::sin(2 * M_PI * formants[f] * t * 0.001f); // kHz to Hz
|
||||
|
||||
// Огибающая (модуляция амплитуды)
|
||||
float envelope = 0.5f + 0.5f * std::sin(2 * M_PI * envelope_freq * t);
|
||||
|
||||
// Добавляем немного шума (дыхание)
|
||||
std::uniform_real_distribution<> breath_noise(-0.1f, 0.1f);
|
||||
float breath = breath_noise(m_gen);
|
||||
|
||||
// И немного низкочастотной модуляции (вибрато)
|
||||
float vibrato = 0.1f * std::sin(2 * M_PI * 5.0f * t); // 5 Hz vibrato
|
||||
|
||||
signal[i] = m_params.m_amplitude * envelope * (value + breath + vibrato);
|
||||
}
|
||||
|
||||
// Нормализуем
|
||||
float max_val = *std::max_element(signal.begin(), signal.end(),
|
||||
[](float a, float b) { return std::abs(a) < std::abs(b); });
|
||||
if (max_val > 0)
|
||||
for (auto& s : signal) s /= max_val;
|
||||
|
||||
// Добавляем дополнительный шум если нужно
|
||||
if (noise == NOISE::YES)
|
||||
{
|
||||
std::uniform_real_distribution<> dist(-m_params.m_noise_level, m_params.m_noise_level);
|
||||
for (auto& s : signal) s += dist(m_gen);
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
|
||||
std::vector<float> signal_generator::three_sines(NOISE noise)
|
||||
{
|
||||
std::vector<float> signal(m_params.m_samples);
|
||||
|
||||
// три разные частоты
|
||||
float f1 = m_params.m_frequency;
|
||||
float f2 = m_params.m_frequency * 2.f;
|
||||
|
||||
// амплитуды
|
||||
float a1 = m_params.m_amplitude;
|
||||
float a2 = m_params.m_amplitude * 0.5f;
|
||||
|
||||
for (int i = 0; i < m_params.m_samples; ++i)
|
||||
{
|
||||
float t = i * 0.02f;
|
||||
signal[i] = a1 * std::sin(2 * M_PI * f1 * t) +
|
||||
a2 * std::sin(2 * M_PI * f2 * t + 3.f/4.f* M_PI);
|
||||
}
|
||||
|
||||
if (noise == NOISE::YES)
|
||||
{
|
||||
std::uniform_real_distribution<> dist(-m_params.m_noise_level, m_params.m_noise_level);
|
||||
for (auto& s : signal) s += dist(m_gen);
|
||||
}
|
||||
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
60
src/utils/signal_generator/signal_generator.hpp
Normal file
60
src/utils/signal_generator/signal_generator.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
|
||||
// Генерирует простую синусоиду и др. полезности см. SIGNAL_TYPE
|
||||
namespace hr
|
||||
{
|
||||
enum class SIGNAL_TYPE
|
||||
{
|
||||
SIN, // Синусоида
|
||||
SQUARE, // Прямоугольный
|
||||
TRIANGLE, // Треугольный
|
||||
SAW, // Пилообразный
|
||||
NOISE_ONLY, // Только шум
|
||||
SPEECH_LIKE, // Типа речь
|
||||
THREE_SINES // Три частоты
|
||||
};
|
||||
|
||||
enum class NOISE
|
||||
{
|
||||
NO,
|
||||
YES
|
||||
};
|
||||
|
||||
// Формула синусоиды
|
||||
// f(t) = A_m sin(2 PI t 1/T + a)
|
||||
// где
|
||||
// a - начальная фаза
|
||||
// t - время замера
|
||||
// 1/T - частота
|
||||
// T - время полного цикла одного периуда колебаний
|
||||
class signal_generator
|
||||
{
|
||||
public:
|
||||
signal_generator() : m_gen(12345) {}
|
||||
|
||||
std::vector<float> generate(SIGNAL_TYPE type, NOISE noise = NOISE::NO);
|
||||
|
||||
public:
|
||||
struct signal_params
|
||||
{
|
||||
float m_amplitude = 1.0f; // A
|
||||
float m_frequency = 1.0f; // 1/T
|
||||
float m_noise_level = 0.7f;
|
||||
int m_samples = 1200;
|
||||
} m_params;
|
||||
|
||||
private:
|
||||
std::vector<float> sin(NOISE noise);
|
||||
std::vector<float> square(NOISE noise);
|
||||
std::vector<float> triangle(NOISE noise);
|
||||
std::vector<float> saw(NOISE noise);
|
||||
std::vector<float> noise_only();
|
||||
std::vector<float> speech_like(NOISE noise);
|
||||
std::vector<float> three_sines(NOISE noise);
|
||||
|
||||
private:
|
||||
std::mt19937 m_gen;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user