%% КЛАСС ДЛЯ РАСЧЕТА КОЭФФИЦИЕНТОВ БИКВАДРАТНЫХ ФИЛЬТРОВ
classdef BiquadFilterDesigner
    %BIQUADFILTERDESIGNER Класс для расчета коэффициентов биквадратных фильтров
    %   Поддерживает: ФНЧ, ФВЧ, полосовые, режекторные фильтры
    
    methods (Static)
        
        %% 1. ФНЧ (Low-Pass Filter)
        function [b, a, coeffs_cmsis] = lpf(fc, Fs, Q)
            % lpf - Расчет коэффициентов ФНЧ через MATLAB функции
            %   fc - частота среза [Гц]
            %   Fs - частота дискретизации [Гц]  
            
            if fc >= Fs/2
                error('Частота среза должна быть меньше Fs/2');
            end
            
            % Используем встроенные функции MATLAB
            if nargin < 3
                % По умолчанию - Баттерворт
                [b, a] = butter(2, fc/(Fs/2), 'low');
            else
                % С указанной добротностью
                [b, a] = butter(2, fc/(Fs/2), 'low');
            end
            
            % Стабилизация коэффициентов            
            [b, a] = BiquadFilterDesigner.stabilize_filter(b, a);
            
            % Формат для CMSIS-DSP [b0, b1, b2, a1, a2]
            coeffs_cmsis = [b(1), b(2), b(3), a(2), a(3)];
        end
        
        %% 2. ФВЧ (High-Pass Filter)
        function [b, a, coeffs_cmsis] = hpf(fc, Fs, Q)
            % hpf - Расчет коэффициентов ФВЧ через MATLAB функции
            %   fc - частота среза [Гц]
            %   Fs - частота дискретизации [Гц]
            
            if fc >= Fs/2
                error('Частота среза должна быть меньше Fs/2');
            end
            
            % Используем встроенные функции MATLAB
            [b, a] = butter(2, fc/(Fs/2), 'high');
            
            % Стабилизация коэффициентов
            [b, a] = BiquadFilterDesigner.stabilize_filter(b, a);
            
            coeffs_cmsis = [b(1), b(2), b(3), a(2), a(3)];
        end
        
        %% 3. Полосовой фильтр (Band-Pass Filter) - ИСПРАВЛЕННЫЙ
        function [b, a, coeffs_cmsis] = bpf(fc, bw, Fs)
            % bpf - Расчет коэффициентов полосового фильтра через MATLAB функции
            %   fc - центральная частота [Гц]
            %   bw - ширина полосы [Гц]
            %   Fs - частота дискретизации [Гц]
            
            f_low = fc - bw/2;
            f_high = fc + bw/2;
            
            if f_high >= Fs/2
                error('Верхняя граница полосы должна быть меньше Fs/2');
            end
            
            % Используем встроенные функции MATLAB
            [b, a] = butter(2, [f_low, f_high]/(Fs/2), 'bandpass');
            
            % Стабилизация коэффициентов
            [b, a] = BiquadFilterDesigner.stabilize_filter(b, a);
            
            coeffs_cmsis = [b(1), b(2), b(3), a(2), a(3)];
        end
        
        %% 4. Режекторный фильтр (Band-Stop/Notch Filter)
        function [b, a, coeffs_cmsis] = bsf(fc, bw, Fs)
            % bsf - Расчет коэффициентов режекторного фильтра через MATLAB функции
            %   fc - центральная частота [Гц]
            %   bw - ширина полосы подавления [Гц]
            %   Fs - частота дискретизации [Гц]
            
            f_low = fc - bw/2;
            f_high = fc + bw/2;
            
            if f_high >= Fs/2
                error('Верхняя граница полосы должна быть меньше Fs/2');
            end
            
            % Используем встроенные функции MATLAB
            [b, a] = butter(2, [f_low, f_high]/(Fs/2), 'stop');
            
            % Стабилизация коэффициентов
            a_stable = a;
            if abs(a(3)) > 0.99
                a_stable(3) = 0.99 * sign(a(3));
            end
            if abs(a(2)) > 1.98
                a_stable(2) = 1.98 * sign(a(2));
            end
            
            b = b;
            a = a_stable;
            
            coeffs_cmsis = [b(1), b(2), b(3), a(2), a(3)];
        end
        
        %% 5. Показать характеристики фильтра
        function show_response(b, a, Fs, filter_name)
            % show_response - Визуализация характеристик фильтра
            %   b, a - коэффициенты фильтра
            %   Fs - частота дискретизации [Гц]
            %   filter_name - название фильтра для заголовка
            
            figure('Position', [100, 100, 1000, 700]);
            
            % АЧХ
            subplot(2,2,1);
            [h, f] = freqz(b, a, 1024, Fs);
            plot(f, 20*log10(abs(h)), 'LineWidth', 2);
            title([filter_name ' - АЧХ']);
            xlabel('Частота [Гц]'); ylabel('Усиление [дБ]');
            grid on;
            
            % ФЧХ
            subplot(2,2,2);
            plot(f, angle(h)*180/pi, 'LineWidth', 2);
            title([filter_name ' - ФЧХ']);
            xlabel('Частота [Гц]'); ylabel('Фаза [градусы]');
            grid on;
            
            % Групповая задержка
            subplot(2,2,3);
            [gd, f_gd] = grpdelay(b, a, 1024, Fs);
            plot(f_gd, gd/Fs*1000, 'LineWidth', 2);
            title([filter_name ' - Групповая задержка']);
            xlabel('Частота [Гц]'); ylabel('Задержка [мс]');
            grid on;
            
            % Импульсная характеристика
            subplot(2,2,4);
            imp_resp = filter(b, a, [1 zeros(1, 99)]);
            stem(0:99, imp_resp, 'filled', 'MarkerSize', 4);
            title([filter_name ' - Импульсная характеристика']);
            xlabel('Отсчеты'); ylabel('Амплитуда');
            grid on;
        end
        
        %% 6. Генерация C-кода для коэффициентов
        function generate_c_code(coeffs, filter_name)
            % generate_c_code - Генерация C-кода для коэффициентов
            %   coeffs - коэффициенты в формате CMSIS [b0, b1, b2, a1, a2]
            %   filter_name - имя фильтра для переменной
            
            fprintf('// Коэффициенты фильтра: %s\n', filter_name);
            fprintf('const float32_t %s_coeffs[5] = {\n', filter_name);
            fprintf('    %.6ff,  // b0\n', coeffs(1));
            fprintf('    %.6ff,  // b1\n', coeffs(2));
            fprintf('    %.6ff,  // b2\n', coeffs(3));
            fprintf('    %.6ff,  // a1\n', coeffs(4));
            fprintf('    %.6ff   // a2\n', coeffs(5));
            fprintf('};\n\n');
        end

        function [b_stable, a_stable] = stabilize_filter(b, a)
            a_stable = a;
            % Ограничиваем коэффициенты a для устойчивости
            if abs(a_stable(3)) > 0.95
                a_stable(3) = 0.95 * sign(a_stable(3));
            end
            if abs(a_stable(2)) > 1.9
                a_stable(2) = 1.9 * sign(a_stable(2));
            end
            b_stable = b;
        end
    end
end