sergeyhaki / m328_test

0 stars 0 forks source link

void freq #1

Open sergeyhaki opened 1 year ago

sergeyhaki commented 1 year ago

void freq(int32_t fout, uint16_t i, uint16_t q){ // Set a CLK0,1,2 to fout Hz with phase i, q (on PLLA) uint8_t rdiv = 0; // CLK pin sees fout/(2^rdiv) if(fout > 300000000){ i/=3; q/=3; fout/=3; } // for higher freqs, use 3rd harmonic if(fout < 500000){ rdiv = 7; fout = 128; } // Divide by 128 for fout 4..500kHz uint16_t d; if(fout < 30000000) d = (16 fxtal) / fout; else d = (32 fxtal) / fout; // Integer part .. maybe 44? if(fout < 3500000) d = (7 fxtal) / fout; // PLL at 189MHz to cover 160m (freq>1.48MHz) when using 27MHz crystal if(fout > 140000000) d = 4; // for f=140..300MHz; AN619; 4.1.3, this implies integer mode if(d % 2) d++; // even numbers preferred for divider (AN619 p.4 and p.6) if( (d (fout - 5000) / fxtal) != (d (fout + 5000) / fxtal) ) d += 2; // Test if multiplier remains same for freq deviation +/- 5kHz, if not use different divider to make same uint32_t fvcoa = d fout; // Variable PLLA VCO frequency at integer multiple of fout at around 27MHz16 = 432MHz // si5351 spectral purity considerations: https://groups.io/g/QRPLabs/message/42662

  ms(MSNA, fvcoa, fxtal);                   // PLLA in fractional mode
  //ms(MSNB, fvcoa, fxtal);
  ms(MS0,  fvcoa, fout, PLLA, 0, i, rdiv);  // Multisynth stage with integer divider but in frac mode due to phase setting
  ms(MS1,  fvcoa, fout, PLLA, 0, q, rdiv);

ifdef F_CLK2

  freqb(F_CLK2);

else

  ms(MS2,  fvcoa, fout, PLLA, 0, 0, rdiv);

endif

  if(iqmsa != (((int8_t)i-(int8_t)q)*((int16_t)(fvcoa/fout))/90)){ iqmsa = ((int8_t)i-(int8_t)q)*((int16_t)(fvcoa/fout))/90; reset(); }
  oe(0b00000011);  // output enable CLK0, CLK1

ifdef x

  ms(MSNA, fvcoa, fxtal);
  ms(MSNB, fvcoa, fxtal);
  #define F_DEV 4
  ms(MS0,  fvcoa, (fout + F_DEV), PLLA, 0, 0, rdiv);
  ms(MS1,  fvcoa, (fout + F_DEV), PLLA, 0, 0, rdiv);
  ms(MS2,  fvcoa, fout, PLLA, 0, 0, rdiv);
  reset();
  ms(MS0,  fvcoa, fout, PLLA, 0, 0, rdiv);
  delayMicroseconds(F_MCU/16000000 * 1000000UL/F_DEV);  // Td = 1/(4 * Fdev) phase-shift   https://tj-lab.org/2020/08/27/si5351%e5%8d%98%e4%bd%93%e3%81%a73mhz%e4%bb%a5%e4%b8%8b%e3%81%ae%e7%9b%b4%e4%ba%a4%e4%bf%a1%e5%8f%b7%e3%82%92%e5%87%ba%e5%8a%9b%e3%81%99%e3%82%8b/
  ms(MS1,  fvcoa, fout, PLLA, 0, 0, rdiv);
  oe(0b00000011);  // output enable CLK0, CLK1

endif

  _fout = fout;  // cache
  _div = d;
  _msa128min512 = fvcoa / fxtal * 128 - 512;
  _msb128=((uint64_t)(fvcoa % fxtal)*_MSC*128) / fxtal;
  //_mod = fvcoa % fxtal;

}

sergeyhaki commented 1 year ago

Для определения сдвига фазы all-pass фильтра на частотах в диапазоне 200-3500 Гц можно вычислить фазовую характеристику фильтра и обработать ее взвешенным интегрированием. Фазовая характеристика фильтра представляет собой зависимость фазового угла от частоты. На основе этой характеристики можно вычислить задержку фильтра и пересчитать ее в сдвиг фазы на заданном диапазоне частот.

Для начала необходимо вычислить фазовую характеристику H(ω) фильтра на всем диапазоне частот. Для этого можно использовать функцию atan2, которая вычисляет арктангенс по двум аргументам, чтобы получить фазовый угол на каждой частоте. Затем нужно вычислить задержку фильтра на каждой частоте. Задержка фильтра может быть вычислена как производная фазовой характеристики по частоте. Для реализации этого вычисления может использоваться численное дифференцирование. Наконец, полученные задержки фильтра можно пересчитать в сдвиг фазы на диапазоне частот от 200 до 3500 Гц.

Пример кода на языке Python для определения сдвига фазы all-pass фильтра на диапазоне частот от 200 до 3500 Гц:

import numpy as np

def allpass_filter(x, b, a, xn=None, yn=None):
    if xn is None:
        xn = np.zeros(len(b)-1)
    if yn is None:
        yn = np.zeros(len(a)-1)
    y = np.zeros(len(x))
    for n in range(len(x)):
        y_ = b[0]*x[n] + b[1]*xn[0] + b[2]*xn[1] - a[1]*yn[0] - a[2]*yn[1]
        xn[1], xn[0] = xn[0], x[n]
        yn[1], yn[0] = yn[0], y_
        y[n] = y_
    return y, xn, yn

def phase_delay(w, h):
    delta_w = np.diff(w)
    delta_h = np.diff(h)
    delta_phi = np.arctan2(delta_h, delta_w)
    delta_phi = np.concatenate(([delta_phi[0]], delta_phi))
    tau = -np.cumsum(delta_phi)/w
    return tau

# Коэффициенты фильтра
b = np.array([1.0, -1.9315, 0.9315])
a = np.array([0.9647, -1.9315, 0.9647])

# Диапазон частот
w = np.logspace(np.log10(200), np.log10(3500), 1000)

# Вычисляем фазовую характеристику фильтра
h = np.angle(np.polyval(b, np.exp(1j*w)) / np.polyval(a, np.exp(1j*w)))

# Вычисляем задержку фильтра
tau = phase_delay(w, h)

# Вычисляем сдвиг фазы на диапазоне частот от 200 до 3500 Гц
f_range = np.where((w>=200) & (w<=3500))[0]
phi = -np.angle(np.exp(-1j*np.cumsum(tau[f_range])*w[f_range]))
phi_deg = np.rad2deg(phi)

# Выводим результат
print(f"Сдвиг фазы на диапазоне частот от 200 до 3500 Гц:")
print(f"Минимальный сдвиг фазы: {np.min(phi_deg):.2f} градусов")
print(f"Максимальный сдвиг фазы: {np.max(phi_deg):.2f} градусов")

В результате выполнения этого кода будет определен сдвиг фазы all-pass фильтра на диапазоне частот от 200 до 3500 Гц.

sergeyhaki commented 8 months ago

% Задание параметров фильтра Fs = 1000; % Частота дискретизации Fpass = [0 500]; % Полоса пропускания фильтра N = 100; % Порядок фильтра

% Создание фильтра filter = designfilt('allpassfir', 'FilterOrder', N, 'PassbandFrequency', Fpass, 'SampleRate', Fs);

% Визуализация АЧХ и ФЧХ фильтра freqz(filter);

% Применение фильтра к сигналу t = 0:1/Fs:1; % Временная ось x = sin(2pi50*t); % Входной сигнал y = filtfilt(filter, x);

% Визуализация входного и выходного сигналов figure; plot(t, x, 'b', t, y, 'r'); xlabel('Time (s)'); ylabel('Amplitude'); legend('Input', 'Output');

sergeyhaki commented 7 months ago

include

// Кнопка const int buttonPin = 2; int lastButtonState = HIGH; int currentButtonState; unsigned long lastDebounceTime = 0; const unsigned long debounceDelay = 50;

// LCD дисплей LiquidCrystal_I2C lcd(0x27, 16, 2); // Инициализация LCD дисплея с адресом 0x27, 16 символами в строке и 2 строками

// Структура для элементов меню struct MenuItem { String name; void (*action)(); };

// Меню MenuItem menuItems[] = { {"Пункт 1", &menuItem1}, {"Пункт 2", &menuItem2}, {"Пункт 3", &menuItem3}, {"Пункт 4", &menuItem4} };

// Текущий выбранный пункт меню int currentMenuItem = 0;

void setup() { // Инициализация кнопки pinMode(buttonPin, INPUT_PULLUP);

// Инициализация LCD дисплея lcd.begin(16, 2); lcd.setCursor(0, 0); lcd.print(menuItems[currentMenuItem].name); }

void loop() { // Считывание состояния кнопки с использованием антидребезга int reading = digitalRead(buttonPin); if (reading != lastButtonState) { lastDebounceTime = millis(); } if (millis() - lastDebounceTime > debounceDelay) { if (reading != currentButtonState) { currentButtonState = reading; if (currentButtonState == LOW) { // При нажатии кнопки выбираем следующий пункт меню currentMenuItem++; if (currentMenuItem >= sizeof(menuItems) / sizeof(MenuItem)) { currentMenuItem = 0; } lcd.clear(); lcd.setCursor(0, 0); lcd.print(menuItems[currentMenuItem].name); } } }

// Выполнение действия для выбранного пункта меню menuItems[currentMenuItem].action(); }

// Действия для каждого пункта меню void menuItem1() { // Код для выполнения действия пункта 1 }

void menuItem2() { // Код для выполнения действия пункта 2 }

void menuItem3() { // Код для выполнения действия пункта 3 }

void menuItem4() { // Код для выполнения действия пункта 4 }