Форум DL2KQ
ВЧ техника => Приемники \ передатчики => Тема начата: ra0ahc от 31 Марта 2019, 08:10:00
-
ФНЧ-КСВметр-автоТЮНЕР
Предлагаю, почти готовую лабораторную работу
начатую на другом ресурсе
-
Схема ксв метра
База взята из N2PK ксв метра
-
ФНЧ
Лабораторные работы по ним уже сделаны
фото того, что получилось уже на плате:
-
Остальные фото:
-
Схема ФНЧ:
-
ФНЧ были сделаны сперва на макетках, но после переноса на печатку все номиналы поплыли
-
Все номиналы емкостей и индуктивностей считались в RFsim
Все индуктивности намотаны на Амидонах
-
Схема тюнера:
....
Работа по нему еще не вилась. Всё запаяно в плату (реле, тр, емкости)
-
На сегодня есть проблема с ксв-метром.
Здесь Брюне, запаянный между фнч и тюнером.
-
Вот уже неделю не могу сбалансировать мост.
Фнч настроен "на всю плату", резистор 50 ом стоИт на выходе платы. Измерения ведутся ОСОй.
Возня с трансформатором продолжается.
Расчет емкостного делителя известен (на фото), но ничего не получается.
-
http://dl2kq.de/pa/1-2.htm
-
Конечно я был там.
Вот вопрос тогда ещё один с учетом опыта Игоря .
Щель разрыва оплётки имеет значения в каком месте будет ?
Просто н2пк предлагает кольцо одеть прямо на оплётку с одним заземлённым концом. И до щели получается порядка 2 см ! На фото очень хорошо видно .
-
У меня один раз получилось сбалансировать, но емкость с1 получилась 20 пик и с2 1400пф резонанс был четкий! И при изменении 50 ом нагрузки на другое скажем 100 или 33 ом обратка реагировала существенно. Правда 1400 пф это плохо , на вч завал сразу - просто кз .
Вот у меня мысль и пошла , что с тр идёт что-то не то .
-
Всё разрисовано и расписано к схеме по Рис. 3
-
Да я очень внимательно все читал и несколько раз.
И даже было частично реализовано, на столько, на сколько плата позволяет. Резонанса нет, и хоть все распаивай и заново переделывай.
Вопрос тот же так и остался.
Расположение щели в оплетке имеет значение?
-
Ладно, если вариантов не осталось, тогда попробую сделать как у Игоря.
А кстати, а Игорь бывает здесь?
-
Провел маленькую лаб. работу.
Запаял всю аналоговую и цифровую часть в латунь. Сдвинул тр на другую сторону кабеля там где нет оплетки, ну и что-то получилось :)
Латунь дала почти 3 дб RL.
Основной прирост дало установка кольца на "щель" в кабеле. Собственно я и ответил на свой вопрос.
-
Емкости с1 с2 2.7пф и 240пф
тр = 600нн кольцо, 7 витков (пробовал 8, 11)
Сейчас провел испытания на 28 мгц, с уменьшением частоты RL растет с 27 дб до 34дб, правда я проверял АЧХ кольца - есть не большой завальчик на 28 но это все в районе 0.5дб . Проверка шла включением кольца как трансформатор 1:1 50-50 ом
-
Уровень входного сигнала от осы 8дбм, больше она не дает. Но даже при таких низких значениях амплитуды, ад8307 справились.
-
Улучшайзинг продолжается!
Запаял второй конец оплетки кабеля на землю, та, что в плотную подходит к кольцу, сразу RL поднялась на 6дб. Теперь разница между 28 и 3.5 практически отсутствует!!!!!
RL это разница между прямой и обратной волнами в дб.
К сожалению прямой расчет с1 с2 по формуле не дает результата из-за емкостных составляющих печатной платы.
-
По факту получилась практически классическая схем моста Брюне.
пришлось поднять с платы емкости с1 и с2 в воздух.
-
Сегодня провел очередной эксперимент.
100Ватт с УМ.
Сразу все накрылось по напряжению с ад8307 на вход ацп - более 2.038 В , это предел для ацп, а для адешки 3 вольта предел.
Пришлось малой кровью вводить делитель напряжения перед ацп 1к и 3 к., к тому же были заменены 0.1 емкости на 1000пф в цепи выходного напряжения, а то ацп успевал прочитать промежуточные значения. Такой расклад нам не годится для тюнера, процессор быстрый!
Теперь схема н2пк уже выглядит немного не такой как у автора.
-
Ну и сделал вывод на мониторчик (две полоски зеленых) - это примерно 100Вт
вывод логарифмический ...возможно спорный момент, пока оставлю там видно будет
-
Занялся тюнером, заодно и переделал клавиатуру. Теперь : RX, TX, TUNER, COMMON клавиатуры. Кнопок катастрофически не хватает.
Еще проблем добавило это проблема с битами для реле. Они получились инвертированы. т.е. надо 10000000 подать чтобы зажечь первую реле с самой маленькой индуктивностью.
Простого решения нет на С, только на Ассемблере. Приходится изголятся.
Процесс идет
-
Во время экспериментов чуть не испугался ....
Блок схема, согласно теме, ФНЧ - КСВметр - ТЮНЕР . Сигнал с генератора я подаю через фнч, настроенного по диапазонам. Если уводить (например 3.6 мгц фильтр) до 5-6 МГц то фильтр дает уже ксв очень высокий. Здесь я и ..... амплитуда на выходе падает а ксв не растет! Прошло пару дней пока я понял что так и должно быть! Нагрузка 50 как была так и осталась и выход фильтра согласован под 50 поэтому ксв и стояло на месте.
-
Кнопок катастрофически не хватает.
Я нагрузил I2C по максимуму: 8 PCA9555, 6 из них на 12 светодиодных индикаторов (8 справа на частоту, 4 слева на дополнительную информацию), оставшиеся 2 поддерживают кнопки. Так как энкодер имеет кнопку, то остается 31 кнопка на всё. Это всё управляет ДДСом, статически, никакого мультиплексирования. Суда по анализатору спектра, лишнего шума не появляется, когда активно кручу энкодер. Но паять приходится очень много выводов...
-
Емкости не менее 330uf повесить надо по питанию процессора по 3.3 вольта
Я вчера прямо на плате процессора это делал тем самым окончательно убрал артефакты при нажатии на Кнопки, хотя раньше их не замечал
По 8 пцашкам... они будут работать пока емкость по i2c не превысит 400 пф
А там , вам же понравилось с ними работать ? Метлесений нет?
-
Кстати у меня в во все трансивере 5 PCA и ещё две сишки и ещё ацп и в е это на i2c - шума нет
А кнопки все сидят на ацп процессора
-
ФНЧ-КСВметр-автоТЮНЕР
Предлагаю, почти готовую лабораторную работу
начатую на другом ресурсе
На каком ресурсе?
-
Ve3kf форум
-
Из за хлопкоп 8 реле 35 ма на каждый , во время работы тюнера (пока в ручном режиме) наблюдались артефакты по приему. Тюнер в моем случаи по приему может работать тоже , причём на передачу своё на приём своё. Помогло 6800uF емкость после стабилизатора (было 20). Также за компанию поставил в питании процессора по 3.3 вольта 330 тантал( уже писал об этом)
-
ЛАБА 1 TUNER ручной режим
частота 3.89
фнч -80м
источник - бэвер длиной 500 м. (dl2kq)
расчет RFsim
-
фото
Первая - было (смотреть 2 маркер)
вторая - стало (смотреть туда же)
вытянул с 85 ом
-
а вот 20 ом уже НЕ вытянул на частоте 2.4МГц, хотя по расчетам индуктивность есть, а емкости не хватило
-
не работает
начинаю все сначала
-
была плохо пропаяна ад8307 - блин!!!
две недели коту под хвост
-
Брюне нормально сбалансировался до RL=30дб
при параллельном подключении еще 50 ом RL падает до 12дб что примерно соответствует ксв 1.9-2
Погрешность в 3 дб присутствует, но можно откалибровать при наличии еще одного ксвметра. У меня нет ксв метров больше.
-
Также был опробован Тадем мач
на маленьком бинокле с 10ю витками в каждом тр
Заработал сразу, но при повышении мощности свыше 5 ватт ксв догонял мощность.
По схеме n7ddc
-
ЛАБА 2
работа фнч при 80-90 ваттах на 80м диапазоне
маркеры на 2ой и 3й гармониках
подавление -53дб
-
Предварительный план по АВТОтюнеру.
Последовательность действий. Вариант 1.
Подготовка:
1. Проверяем стоит ли на передаче. Если нет - сообщение на экран.
2. Подать тон, и проверить ксв и мощность. Если мощность маленькая или наоборот большая - выкл ПТТ и сообщение на экран. С КСВ пока вопрос (не понятен ксв обрыва или отсутствия антенны)
3. Посмотреть в памяти, есть ли на данную частоту значения LC. Если есть то читаем и устанавливаем. Проверяем КСВ, если ок, тогда СТОП и сообщение на экран.
Настройка:
это два параллельных процесса: замер и анализ
1. замер.
2. ждем пока замерит (при 16 битах ацп не более 15 замеров в сек.).
3. анализ
4. Если ксв более 1.2 то пробуем L+1 , ждем пока перекинет реле 10ms.
5. Замер. Сравниваем с предыдущим значением и еще L+1 замер опять. Если ... и так далее
.... еще думаю и готовлю основную программу к инсталяции в нее подпрограммы автотюнинга
-
Провел подготовительную работу в программе - поставил защиты и вывод информации на экран
-
Сложность в написании программы состоит в то, что нельзя использовать прямые задержки как это делается во многих программах типа: старт ацп на чтение...пауза 20мсек...чтение ацп...анализ, переключение реле....пауза 10мс( для реле)...анализ ... ну и тд . такой стиль называется : первый класс, первая четверть, и он полностью убирает возможность многозадачности в современном процессоре. Процессор не должен простаивать - это утопия
На самом деле, все эти процессы должны работать параллельно! Когда вся программа ждет пока реле захлопница и начнется замер ацп, можно много чего еще поделать, например прорисовка в паузах есть очень хороший стиль. Ну а за паузы отвечает таймер, он проставит маячки когда надо. К сожалению из-за i2c нельзя использовать прямой вызов процедуры из таймера, этот возможный конфликт уже не разобрать (может, прерывание i2c прервать эту самую i2c, например когда ацп считывалось).
Так что процесс написания программы не быстрый, при параллельном мышлении много нюансов и флагов.
Вот пример старта тюнера. Контроль контроль и контроль, одни операторы if
if (pttYN && tunerAutoStartYN) { ///потом добавить проверку на наличие тона
if (tunerAutoJustStartedYN) {//рутина перед стартом
tunerAutoJustStartedYN = 0;
if (v_to_dbW(SWR_ch_value[1]) - v_to_dbW(SWR_ch_value[1]) < 3) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " HI SWR >6. Check Ant ");
return;
}
if (v_to_dbW(SWR_ch_value[0]) < 0) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need MORE power or Tone. ");
return;
}
if (v_to_dbW(SWR_ch_value[0]) > 12) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need less 13dbW power. ");
return;
}
//сохраним значения до старта (с учетом диапазона) надо для не удачной настройки или отмены
tunerBeforeValueLC[nowBandIsNumber][0] = tunerMore50 ?
(uint8_t) (tunerRxNowLCIs[nowBandIsNumber][0] & 1)
://подставим бит кондера
(uint8_t) (tunerRxNowLCIs[nowBandIsNumber][0] & (~1));
tunerBeforeValueLC[nowBandIsNumber][1] = tunerRxNowLCIs[nowBandIsNumber][1];
//первое текущее лучшее значения
tunerLastBestPSR[0]=SWR_ch_value[0];//power
tunerLastBestPSR[1]=SWR_ch_value[1];//swr
tunerLastBestPSR[2]=SWR_ch_value[0]-SWR_ch_value[1];//RL
}//конец рутины
if(tunerSwrReady==2 && tunerRaleyTimer==0){ //если ксв замерили и реле сработало
//First Step
if(tunerTuningStep==0) {//последовательнай проход
//analyse
if(tunerLastBestPSR[2]>SWR_ch_value[0]-SWR_ch_value[1]) {
tunerLastBestPSR[0]=SWR_ch_value[0];//RL
}
if(0<tunerCircleC && tunerCircleC<=255){
tunerCircleC++;
tunerSwrReady=0;
tuner_write(tunerMore50 ?
(uint8_t) (tunerCircleL & 1)
://подставим бит кондера
(uint8_t) (tunerCircleL & (~1)),
tunerCircleC);
tunerRaleyTimer=40;
}
}
}
-
Решения пока так и нет.
Полистал инет, достаточно не много инфы про алгоритмы.
Не плохой вариант с датчиком фазы, но его нет.
Простой перебор "не катит".
-
https://www.matburo.ru/tv_komb.php ;)
-
Хороший сайт, только я как раз и хотел от этого уйти.
Вот пример, по этому примеры я анализатор спектра делал для нащих нужд 0-4000Гц :
-
Вот Геннадий Завидовский предложил:
Алгоритм такой... На минимуме индуктивности и емкость. Начинаю увеличивать индуктивность пока не начнет увеличтватьс ксв. Потом увеличиваю ёмкость пока не начнет увеличиваться ксв.
Потом то же самое на другом положении подклбчения конденсаторов.
То где меньше результат - принимается.
Да, шаги неравномерные.
Все есть в исходниках - https://github.com/ua1arn/hftrx/blob/master/tc1.c 0 искать по слову TUNER
источник http://www.cqham.ru/forum/member.php?1595-Genadi-Zawidowski
-
Алгоритм работает!
за 6 итераций вышел на мин ксв.
-
Еще раз посмотрел алгоритм Геннадия.... он останавливает программу на время замера и переброски реле.
Это не наш вариант, но сам алгоритм правильный.
Более того, я его буду использовать для PA1500 на 2-ГУ74 с моторами, с адаптацией под П-контур.
Дя Г-образного согласования это оптимум, из простого подхода(на сегодня без фазового детектора).
-
Еще раз посмотрел алгоритм Геннадия.... он останавливает программу на время замера и переброски реле.
Это не наш вариант, но сам алгоритм правильный.
Более того, я его буду использовать для PA1500 на 2-ГУ74 с моторами, с адаптацией под П-контур.
Дя Г-образного согласования это оптимум, из простого подхода(на сегодня без фазового детектора).
Ну, лишь бы только на бумаге не осталось... ;)
-
Ну, лишь бы только на бумаге не осталось... ;)
Да уже много сделано
Печатки, БП
-
Процедура тюнера с коментами (смайлики не мои в листинге, это сам сайт подменяет зачем-то):
P.S. была протестирована и забракована в последствии.
void tuner_auto_start(void) //auto-tune
{
if (pttYN && tunerAutoStartYN) { //todo потом добавить проверку на наличие тона
if (tunerAutoJustStartedYN) {//рутина перед стартом
tunerAutoJustStartedYN = 0;
tunerTuningStep = 0;
tunerTempValueIdx = 0;
if (v_to_dbW(SWR_ch_value[1]) - v_to_dbW(SWR_ch_value[1]) < 3) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " HI SWR >6. Check Ant ");
return;
}
if (v_to_dbW(SWR_ch_value[0]) < 0) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need MORE power or Tone. ");
return;
}
if (v_to_dbW(SWR_ch_value[0]) > 12) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need less 13dbW power. ");
return;
}
tunerCircleL = tunerCircleC = tunerMore50 = 0;//итерации в 0 начнем все сначала
///установка степа в зависимости от диапазона
if (nowBandIsNumber < 3) {
tunerStepL = 4;
tunerStepC = 8;
tunerMaxC = 255; //стартовая емкость
}
if (nowBandIsNumber >= 3 && nowBandIsNumber < 5) {
tunerStepL = 2;
tunerStepC = 4;
tunerMaxC = 200;//стартовая емкость
}
if (nowBandIsNumber >= 5 && nowBandIsNumber < 7) {
tunerStepL = 1;
tunerStepC = 2;
tunerMaxC = 150;//стартовая емкость
}
if (nowBandIsNumber >= 7) {
tunerStepL = 1;
tunerStepC = 1;
tunerMaxC = 127;//стартовая емкость
}
//обнулим значения до старта (с учетом диапазона)
tunerBeforeValueLC[nowBandIsNumber][0] = 0;
tunerBeforeValueLC[nowBandIsNumber][1] = tunerMaxC;
tunerBeforeValueLC[nowBandIsNumber][2] = 0;
//первое и текущее -лучшее значения
tunerLastBestPSR[0] = SWR_ch_value[0];//power
tunerLastBestPSR[1] = SWR_ch_value[1];//swr
tunerLastBestPSR[2] = SWR_ch_value[0] - SWR_ch_value[1];//RL
tunerLastBestPSR[3] = tunerMore50;//кондер
}//конец рутины
if (tunerSwrReady == 2 && tunerRaleyTimer == 0) { //если ксв замерили и реле сработало
//analyse
if (tunerLastBestPSR[2] <= SWR_ch_value[0] - SWR_ch_value[1]) {//если рл лучше тогда сохраним это результат
//ADC
tunerLastBestPSR[0] = SWR_ch_value[0];//power
tunerLastBestPSR[1] = SWR_ch_value[1];//reflected
tunerLastBestPSR[2] = SWR_ch_value[0] - SWR_ch_value[1];//RL
tunerLastBestPSR[3] = tunerMore50;//кондер
//L C C50
tunerBeforeValueLC[nowBandIsNumber][0] = tunerCircleL;
tunerBeforeValueLC[nowBandIsNumber][1] = tunerCircleC;
tunerBeforeValueLC[nowBandIsNumber][2] = tunerMore50;
//условие выхода из настройки
if ((100 * (v_to_dbW(SWR_ch_value[0]) - v_to_dbW(SWR_ch_value[1]))) >= tunerTargetRL) {
tunerAutoStartYN = 0; //stop
pttYN = 0;// птт выкл
// //сохраним значения
// tunerBeforeValueLC[nowBandIsNumber][0] = tunerCircleL;
// tunerBeforeValueLC[nowBandIsNumber][1] = tunerCircleC;
// tunerBeforeValueLC[nowBandIsNumber][2] = tunerMore50;
warningOnDisplay((uint8_t *) " Tuning was OK ");
//todo добавить запись во флеш
return;
}
} else { //если нашли хуже вариант (только основной итерации)
if(tunerTuningStep) {
tuner_L_or_C_YN = ~tuner_L_or_C_YN; // 0-тюним L, ff-тюнем С меняем местами
//вспоминаем лучшее значении по L C C50
tunerCircleL=(uint8_t)tunerBeforeValueLC[nowBandIsNumber][0];
tunerCircleC=(uint8_t)tunerBeforeValueLC[nowBandIsNumber][1];
tunerMore50=(uint8_t)tunerBeforeValueLC[nowBandIsNumber][2];
//продолжаем поиск липо по С либо Л
}
}
//если все прошел то выход
if (!tunerCircleC && tunerCircleL == 127) { //C=0 L=127
warningOnDisplay((uint8_t *) " Tuner has MAX LC ");
return;
}
//старт итераций
if (!tunerTuningStep) { //......1 старт итераций 4+4 должно хватить для понимания куда цепляем емкость
tunerTempValueIdx++; //следующая итерация
//меняем напрвление
if (tunerMore50) {//и если это опять 0 тогда увиличивем L на шаг.
tunerMore50 = 0;
tunerCircleL += tunerStepL;
} else tunerMore50 = 1; //делаем замер в другом напрвлении
if (tunerTempValueIdx == 8) tunerTuningStep = 1; // выход , переход к основным итерациям
} else { ///...........2 старт основных итераций
if(tuner_L_or_C_YN){//тюним С в обратном напрвлении
tunerCircleC-=tunerStepC;
}else {//тюним Л на возрастание
tunerCircleL+=tunerStepL;
}
}
// end
tunerSwrReady = 0;// init to start adc
//update relays
tuner_write(tunerMore50 ?
(uint8_t) (tunerCircleL & 1)
://подставим бит кондера
(uint8_t) (tunerCircleL & (~1)),
tunerCircleC);
tunerRaleyTimer = 40; // ini timer of relay
}
}
if (!pttYN && tunerAutoStartYN) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need PTT. Tuning off. ");
}
}
-
описание переменных:
//auto tune var
uint8_t tunerAutoStartYN = 0;
uint8_t tunerAutoJustStartedYN = 0; //тюнер только начал тюнить
int16_t tunerBeforeValueLC[10][3];//значение L C и кондер перед началом работы тюнера
uint32_t tunerLastBestPSR[4];//последнее лучшее значение POWer SWR RL Кондер
uint8_t tunerTempValueIdx = 0; //индекс прохода во время поиска куда подключить кондер
uint8_t tunerMore50 = 1; //если больше чем 50 ом перебрасывыем кондер к 1-антенне(больше 50ом) 0-тюнер(меньше 50)
uint8_t tunerStepL = 1;//шаг перестройки Л
uint8_t tunerStepC = 1;//шаг перестройки С
uint8_t tunerMaxC = 0;//max С for every band 0..255
uint8_t tuner_L_or_C_YN = 0xff;// 0-тюним L, ff-тюнем С
uint16_t tunerTargetRL = 2800; //лучшее рл потом стоп (28.00дб)
uint8_t tunerSwrReady = 0; //идет замер ксв, 2-готово
uint8_t tunerTuningStep = 0; //этапы тюнинга
uint8_t tunerCircleL = 0; //итерация по индуктивности
uint8_t tunerCircleC = 0;// итерация по емкости
uint8_t tunerRaleyTimer = 0;//таймер ожидания срабатывания реле
-
Запись в плату:
void tuner_write(uint8_t l, uint8_t c) {
uint8_t y = 0x1;//эту будем двигать для маски
uint8_t res = 0;
//зеркальное переделка байта
l = (uint8_t) (l & 0xF0) >> 4 | (uint8_t) (l & 0x0F) << 4;
l = (uint8_t) (l & 0xCC) >> 2 | (uint8_t) (l & 0x33) << 2;
l = (uint8_t) (l & 0xAA) >> 1 | (uint8_t) (l & 0x55) << 1;
//установка битов последоватильно от меньшнго к большему емкостей
for (int i = 0; i < 8; i++) {
if (c & y) res |= tunerTableC;
y <<= 1;
}
c = res;
// l &= ~1;// первый бит в 0 <50ом
//0= <50 ,(l|=1;) 1= >50ом
// l |= 1;//>50ом
char buf[10];
BSP_LCD_SetFont(&Font16);
sprintf((char *) buf, "L=%03d ", l);
BSP_LCD_DisplayHStringAt(0, 150, (uint8_t *) buf, LEFT_MODE);
sprintf((char *) buf, "C=%03d ", c);
BSP_LCD_DisplayHStringAt(0, 170, (uint8_t *) buf, LEFT_MODE);
sprintf((char *) buf, "=%d ", tunerMore50);
BSP_LCD_DisplayHStringAt(60, 170, (uint8_t *) buf, LEFT_MODE);
uint8_t buferWT[3] = {0b00000010, l, c};
while (HAL_I2C_Master_Transmit(&hi2c3, TUNER_TUNER_PCA9555_ADRESS, (uint8_t *) &buferWT, (uint16_t) 3,
(uint32_t) 500) != HAL_OK) {
BSP_LCD_DisplayHStringAt(0, 150, "tuRx-err", LEFT_MODE);
};
};
-
АЦП чтение двух каналов:
///check swr, read ADC
void read_swr(void) {
if (!pttYN) return;
if (!tunerAutoStartYN || (tunerAutoStartYN && tunerSwrReady < 2 && tunerRaleyTimer == 0)) {
uint8_t read_buf[4];
uint8_t config[1] = {0};
//1
if (numberOfChanel == 1 && SWR_ch_started[1] == 0 && SWR_ch_time == 0) {
config[0] = 0b10101000;
//1 = Initiate a new conversion
// 01 =channel
// 0 = One-Shot
// 10= 16 bits
// 00= x1 pga
while (HAL_I2C_Master_Transmit(&hi2c3, TUNER_SWR_MCP3426_ADRESS_WR, (uint8_t *) &config, 1, 500) !=
HAL_OK) { BSP_LCD_DisplayHStringAt(0, 130, "error mcp3426", LEFT_MODE); };
SWR_ch_started[1] = 1;
SWR_ch_started[0] = 0;
SWR_ch_time = 70; //70 для 16бит
}
if (numberOfChanel == 1 && SWR_ch_started[1] == 1 &&
SWR_ch_time == 0) {//если 1 канал, стартанул и время истекло тогда..
while (HAL_I2C_Master_Receive(&hi2c3, TUNER_SWR_MCP3426_ADRESS_RD, read_buf, 4, 500) != HAL_OK) {
BSP_LCD_DisplayHStringAt(0, 20, "error read mcp3426", LEFT_MODE);
};
SWR_ch_value[numberOfChanel] = (((read_buf[0]) << 8) | read_buf[1]);
//преобразование в dbm
SWR_ch_value[numberOfChanel] = (uint16_t) (SWR_ch_value[numberOfChanel] / v_to_dbm);
needDrawSwrBarYN = 1;
needToDrawYN = 1;
SWR_ch_started[1] = 0;
//SWR_ch_started[0]=1;
numberOfChanel = 0;
tunerSwrReady++;//2-готово
}
//0
if (numberOfChanel == 0 && SWR_ch_started[0] == 0 && SWR_ch_time == 0) {
config[0] = 0b10001000;
//1 = Initiate a new conversion
// 00 =channel
// 0 = One-Shot
// 10= 16 bits
// 00= x1 pga
while (HAL_I2C_Master_Transmit(&hi2c3, TUNER_SWR_MCP3426_ADRESS_WR, (uint8_t *) &config, 1, 500) !=
HAL_OK) { BSP_LCD_DisplayHStringAt(0, 130, "error mcp3426", LEFT_MODE); };
SWR_ch_started[0] = 1;
SWR_ch_time = 70; //70 для 16бит
}
if (numberOfChanel == 0 && SWR_ch_started[0] == 1 && SWR_ch_time == 0) {
//если 1 канал, стартанул и время истекло тогда..
while (HAL_I2C_Master_Receive(&hi2c3, TUNER_SWR_MCP3426_ADRESS_RD, read_buf, 4, 500) != HAL_OK) {
BSP_LCD_DisplayHStringAt(0, 20, "error read mcp3426", LEFT_MODE);
};
SWR_ch_value[numberOfChanel] = (((read_buf[0]) << 8) | read_buf[1]);
SWR_ch_value[numberOfChanel] = (uint16_t) (SWR_ch_value[numberOfChanel] / v_to_dbm);
SWR_ch_started[0] = 0;
numberOfChanel = 1;
tunerSwrReady++;//2-готово
}
//если данные изменились то перерисуем
if (SWR_ch_oldValue[0] != SWR_ch_value[0] || SWR_ch_oldValue[1] != SWR_ch_value[1]) {
needDrawSwrBarYN = 1;
needToDrawYN = 1;
//обновим старые на новые данные
SWR_ch_oldValue[0] = SWR_ch_value[0];
SWR_ch_oldValue[1] = SWR_ch_value[1];
}
}
}
-
Выше показанный алгоритм работает не корректно, пропускает минимум (он был первым).
Переделал весь алгоритм. Изменил сам себе - поставил задержки при чтении каналов АЦП прямо в процедуре (теперь программа останавливается). Увеличил точность замера в 10 раз на АЦП (было с точности на 1мВ, сейчас 100uV). Упростил практически всё. Вечером посмотрим, что из этого вышло.
Пока не тестировал.
-
На будущие ...надо "эту" серию АЦП ставить.
-
Ручной прогон алгоритма. 4 итерации до ксв 1.10
-
Нашёл ошибку в управлении железом
Тесты продолжаются, но пока алгоритм работает очень не стабильно. Разные замеры получаются при одинаковых установках реле. Стукаешь легонько по реле и обратка меняется
-
Очередная версия процедуры поиска.
void tuner_auto_start(void) //auto-tune
{
if (pttYN && tunerAutoStartYN) { //todo потом добавить проверку на наличие тона
if (tunerAutoJustStartedYN) {//рутина перед стартом
tunerAutoJustStartedYN = 0;
tunerTuningStep = 0;//этапы тюнинга
tunerTempValueIdx = 0;//индекс прохода во время поиска куда подключить кондер
tuner_L_or_C_YN = 0xff;// 0-тюним L, ff-тюнем С
tunerBedIterationCount=5;//сколько перезапусков для поиска
tunerNoGoodYN = 0; // итерация по Л С оба плохие 2=плохо 0=сначала
/*
// if (v_to_dbW(SWR_ch_value[1]) - v_to_dbW(SWR_ch_value[1]) < 3) {
// tunerAutoStartYN = 0;
// warningOnDisplay((uint8_t *) " HI SWR >6. Check Ant ");
// return;
// }
// if (v_to_dbW(SWR_ch_value[0]) < 0) {
// tunerAutoStartYN = 0;
// warningOnDisplay((uint8_t *) " Need MORE power or Tone. ");
// return;
// }
*/
if (v_to_dbW(SWR_ch_value[0]) > 15) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need less 13dbW power. ");
return;
}
warningOnDisplay((uint8_t *) " Tuning... ");
tunerMore50 = 0;//итерации в 0 начнем все сначала
tunerCircleL = 0;
///установка степа в зависимости от диапазона
if (nowBandIsNumber < 3) {
tunerStepL = 2;
tunerStepC = 8;
tunerMaxC = 255; //стартовая емкость
}
if (nowBandIsNumber >= 3 && nowBandIsNumber < 5) {
tunerStepL = 1;
tunerStepC = 2;
tunerMaxC = 200;//стартовая емкость
}
if (nowBandIsNumber >= 5 && nowBandIsNumber < 7) {
tunerStepL = 1;
tunerStepC = 2;
tunerMaxC = 150;//стартовая емкость
}
if (nowBandIsNumber >= 7) {
tunerStepL = 1;
tunerStepC = 2;
tunerMaxC = 127;//стартовая емкость
}
tunerCircleL = tunerStepL;
tunerCircleC = tunerMaxC;
//обнулим значения до старта (с учетом диапазона)
tunerBeforeValueLC[nowBandIsNumber][0] = 0;
tunerBeforeValueLC[nowBandIsNumber][1] = tunerMaxC;
tunerBeforeValueLC[nowBandIsNumber][2] = 0;
//первое и текущее -лучшее значения
tunerLastBestPSR[0] = 0;//power
tunerLastBestPSR[1] = 0;//swr
tunerLastBestPSR[2] = 0;//RL
tunerLastBestPSR[3] = tunerMore50;//кондер
}//конец рутины
//
//
//ВЫХОД если все прошел то выход
//
//
if (!tunerCircleC && tunerCircleL == 127) { //C=0 L=127
warningOnDisplay((uint8_t *) " Tuner has MAX LC ");
return;
}
//
if ((100 * (v_to_dbW(SWR_ch_value[0]) - v_to_dbW(SWR_ch_value[1]))) >= tunerTargetRL) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Tuner OK ");
tuner_write(tunerBeforeValueLC[nowBandIsNumber][2] ?
(uint8_t) (tunerBeforeValueLC[nowBandIsNumber][0] | 0x80)
://подставим бит кондера
(uint8_t) (tunerBeforeValueLC[nowBandIsNumber][0] & 0x7f),
(uint8_t) tunerBeforeValueLC[nowBandIsNumber][1]);
return;
}
//
//
//analyse
//
//
read_swr_tuner();//read swr ADC
rl = SWR_ch_value[0] - SWR_ch_value[1];
if (rl >> 2 >= tunerLastBestPSR[2] >> 2 || (!tunerLastBestPSR[0] && !tunerLastBestPSR[1])
) {//если рл лучше тогда сохраним это результат (загрубили на ..) или начало
//ADC
tunerLastBestPSR[0] = SWR_ch_value[0];//power uV
tunerLastBestPSR[1] = SWR_ch_value[1];//reflected uV
tunerLastBestPSR[2] = rl;//RL uV
tunerLastBestPSR[3] = tunerMore50;//кондер
//L C C50
tunerBeforeValueLC[nowBandIsNumber][0] = tunerCircleL;
tunerBeforeValueLC[nowBandIsNumber][1] = tunerCircleC;
tunerBeforeValueLC[nowBandIsNumber][2] = tunerMore50;
tunerNoGoodYN = 0; // итерация по Л С оба плохие 2=плохо 0=с начала
tunerBedIterationCount=5;//сколько перезапусков для поиска
//условие выхода из настройки
} else { //если хуже вариант (только основной итерации)
if (tunerTuningStep) {
if (tunerNoGoodYN < 2) {// 2=плохо 0=с начала
if (tuner_L_or_C_YN && tunerStepC)//вернем С назад и еще раз но с Л
tunerCircleC =(tunerCircleC+tunerStepC<0xff) ? (tunerCircleC+tunerStepC):(uint8_t)0xff;
if (!tuner_L_or_C_YN && tunerStepL) //вернем Л назад и еще раз с С
tunerCircleL = (tunerCircleL - tunerStepL >= 0) ? (tunerCircleL - tunerStepL) : (uint8_t) 0;
tunerNoGoodYN++;// 2=плохо
tuner_L_or_C_YN = ~tuner_L_or_C_YN; // 0-тюним L, ff-тюнем С меняем местами
} else {//оба прохода по Л и С были плохими. Что дальше?
tunerBedIterationCount--;//сколько перезапусков для поиска
//вернем все к лучшему варианту и попробуем еше раз
tunerCircleL = (uint8_t) tunerBeforeValueLC[nowBandIsNumber][0];
tunerCircleC = (uint8_t) tunerBeforeValueLC[nowBandIsNumber][1];
tunerMore50 = (uint8_t) tunerBeforeValueLC[nowBandIsNumber][2];
tuner_L_or_C_YN = 0xff; //начнем с С
//если итерации кончились - выход. c лучшеми измерениями.
if(!tunerBedIterationCount){//если итерации кончились - выход.
tunerAutoStartYN = 0;
tuner_write(tunerBeforeValueLC[nowBandIsNumber][2] ?
(uint8_t) (tunerBeforeValueLC[nowBandIsNumber][0] | 0x80)
://подставим бит кондера
(uint8_t) (tunerBeforeValueLC[nowBandIsNumber][0] & 0x7f),
(uint8_t) tunerBeforeValueLC[nowBandIsNumber][1]);
warningOnDisplay((uint8_t *) " Tuner bad iter. ");
return;
}
}
}
}
//
//
//старт итераций
//
//
if (!tunerTuningStep) { //......1 STEP старт итераций 4+4 должно хватить для понимания куда цепляем емкость
tunerTempValueIdx++; //следующая итерация из 16
//меняем напрвление
if (tunerMore50) {//и если это опять 0 тогда увиличивем L на шаг.
tunerMore50 = 0;
tunerCircleL += tunerStepL;
} else
tunerMore50 = 1; //делаем замер в другом напрвлении
if (tunerTempValueIdx == 8) {
tunerTuningStep = 1;
tunerCircleL = 0;
tunerCircleC = tunerMaxC;
tunerLastBestPSR[0] = 0;//power
tunerLastBestPSR[1] = 0;//swr
tunerLastBestPSR[2] = 0;//RL
// выход , переход к основным итерациям
}
} else { ///...........2 STEP старт основных итераций
if (tuner_L_or_C_YN) {//тюним С в обратном напрвлении
if (tunerCircleC - tunerStepC >= 0) {
if ((v_to_dbW(SWR_ch_value[0]) - v_to_dbW(SWR_ch_value[1]) > 20)) {
tunerCircleC--;
tunerStepC=1;
}
else
tunerCircleC -= tunerStepC;
} else
tunerCircleC = 0;
} else {//тюним Л на возрастание
if (tunerCircleL + tunerStepL <= 127) {
if ((v_to_dbW(SWR_ch_value[0]) - v_to_dbW(SWR_ch_value[1]) > 20)) {
tunerCircleL++;
tunerStepL=1;
}
else
tunerCircleL += tunerStepL;
} else
tunerCircleL = 127;
}
}
// end
//
//
//
//update relays
tuner_write(tunerMore50 ?
(uint8_t) (tunerCircleL | 0x80)
://подставим бит кондера
(uint8_t) (tunerCircleL & 0x7f),
tunerCircleC);
tunerRaleyTimer = 5; // ini timer of relay
while (tunerRaleyTimer) {}
//}
}
if (!pttYN && tunerAutoStartYN) {
tunerAutoStartYN = 0;
warningOnDisplay((uint8_t *) " Need PTT. Tuning off. ");
}
}
-
Надо еще второй сценарий приделать -это проход по емкости от 0...255 (сейчас 255...0)
-
Что-то вы давно дневник не обновлял...
Скучно.
-
Программирую !!! Это не очень красочно !!! Уже третий алгоритм пробую . Программированием очень много время занимает . Сижу , ноутбук на коленях , трансивер на боку - тестирую работу тюнера. Пока автомат который работает сам - тупее чем я ))) у меня лучше настраивается в ручном режиме... пока )))
Уже три дня в таком режиме !
-
Вот пример дискретного анализа (реальный):
АД8307 выдает от 0.6в до 2.4в (2.4 в это 100Вт на выходе) , измерить могу только с шагом 12 битами (14 со сдвигом 2) с АЦП - это 8192 варианта.
Сюда подсыпем перца, в виде дриблинга АЦП (это 2 бита, которы я сдвинул), девиацию выходного сигнала (наверное ...не знаю почему) ну и самое веселое это контакты реле (причем реле Омрон ...дорогие). И все это замесим в цикл.
-
Вот основной цикл поиска до 90% от ручной настройки дает!!!
//анализ по 2 шагу.
if (tunerTuningStep == 2) {
uint8_t exit = 3;
uint32_t rlNew = 0;//tunerLastBestPSR[2];//RL uV;
uint32_t rlBest = tunerLastBestPSR[2];//лучший рл в цикле uV
uint8_t cNow = tunerMaxC;// (uint8_t)tunerLastBestValueLC[nowBandIsNumber][1];
uint8_t lNow =0;// (uint8_t)tunerLastBestValueLC[nowBandIsNumber][0];;
uint8_t cBest = 0;
uint8_t lBest = 0;
uint8_t max=40;
int8_t min=-40;
// uint8_t c50Best = tunerMore50;
uint8_t orLC = 0xff; // 0-тюним L, ff-тюнем С, меняем местами
while (exit) {
int lastFor = 0xff;//последний в цикле лучший
for (int i = min; i <= max; i++) {
int8_t dropCircle=0;//пропустить цикл да нет
if (orLC) {
if ((int)cNow - i <= 255 && (int) cNow - i >= 0)cNow -= i;
else dropCircle=1;//пропустить этот цикл
} else {
if ((int)lNow + i >= 0 && (int)lNow + i <= 0x7f)lNow += i;
else dropCircle=1;//пропустить этот цикл
}
if (!dropCircle) {
tuner_write(tunerMore50 ?
(uint8_t) (lNow | 0x80)
://подставим бит кондера
(uint8_t) (lNow & 0x7f),
cNow);
tunerRaleyTimer = 20; // ini timer of relay
while (tunerRaleyTimer) {}
read_swr_tuner();//read swr ADC
rlNew = SWR_ch_value[0] - SWR_ch_value[1];//RL
if (rlNew >>1 > rlBest>>1 ) {
rlBest = rlNew;
cBest = cNow;
lBest = lNow;
lastFor = i;
tunerCircleC = cBest;
tunerCircleL = lBest;
rl = rlBest;
exit = 3;
tunerSaveBest();
//c50Best=tunerMore50;//потом может пригодится если напрвление выбрано не правильно
}
}
}
//если крутим -С
if (orLC && lastFor == min) { //крайнее лучшее положение C крутить
cNow = cBest;
}
//если крутим +L
if (!orLC && lastFor == max) { //крайнее лучшее положение L продолжем еще крутить
lNow = lBest;
}
//если в данном цикле больше небыло хороших результатов
if (lastFor == 0xff ) {
exit--;
orLC = ~orLC;
}
if (lastFor > min && lastFor < max){
if(orLC)cNow = cBest;
if(!orLC)lNow = lBest;
orLC = ~orLC;//меняем Л С местами
}
}
char bufSwr[15];
int ss = (int) (100*rlBest/ 20000); //0.02v/db
sprintf((char *) bufSwr, "RLv=%05d C=%03d L=%03d", ss, cBest,lBest);
BSP_LCD_DisplayHStringAt(61, 206, (uint8_t *) bufSwr, LEFT_MODE);
tuner_write(tunerLastBestValueLC[nowBandIsNumber][2] ?
(uint8_t) (lBest | 0x80)
://подставим бит кондера
(uint8_t) (lBest & 0x7f),
(uint8_t) cBest);
tunerAutoStartYN = 0;
return;
}
}
//}
-
В инете нет таких алгоритмов (или я плохо искал)
-
100% как руками !!!!
Процедура рабочая.
-
до и после настройки
смотреть RL db
-
эта
-
Грубый алгоритм
-
Расклад по L C
//реальные емкости pf (8 штук)
uint16_t tunerCPF[][2] = {
{0b00000001, 2},
{0b00000010, 4},
{0b00000100, 12},
{0b00001000, 24},
{0b00010000, 54},
{0b00100000, 115},
{0b01000000, 225},
{0b10000000, 580}
};
//реальные индуктивности nH (7 штук)
uint16_t tunerLNH[][2] = {
{0b00000001, 22},
{0b00000010, 63},
{0b00000100, 125},
{0b00001000, 252},
{0b00010000, 470},
{0b00100000, 990},
{0b01000000, 2200}
};
-
Особенность настройки
С: уходит почти до 0 и потом вместе с Л начинает расти.
-
Итак итог сегодняшнего вечера:
Я добавил адаптивный алгоритм выхода из итерации!
Я ввел понятие фазы (не путать с аналоговыми делами) теперь я отслеживаю куда идет итерация вверх или вниз и в зависимости от этого выбираю стартовую точку для следующей итерации. Это привело к уменьшению бестолковых мини-итераций в рамках большой итерации.
Эти два факта привели алгоритм к полной адаптивности. И я даже пробовал отключать подчисточный цикл перебором в конце, вроде без него тоже находит КСВ 1.
Осталось сделать адаптивный шаг и "нас не догонят".
-
С моей стороны тема закрыта
Считаю , раскрыл полностью от схемы до программы.
Все листинги программы есть. Еще бы видосик сюда залить как работает, но ресурс не дает больше 2 мгб заливать.
Теперь только полные испытания в составе трансивера на базе rw3fy Ильи Усихина, который я делаю уже 1.5 года!!! Все смонтировано, все работает, осталось немного коммутации и можно закрывать крышки.
-
Щель в оплетке должна быть между припаянными боковыми шайбами (где именно между ними неважно).
Принцип такой: трансформатор тока должен "жить" внутри коаксиальной линии. В идеале, его следует засунуть под оплетку коаксиала. Но т.к. трансформатор туда физически не влезет, то на оплетке кабеля пришлось сделать "вздутие" оплетки в виде боковых шайб и внешней перемычки между ними. И в это "вздутие" спрятать трансформатор тока.
В аттаче красной стрелкой показан путь тока по "оплетке".
PS. Что-то не то случилось с форумом, сообщение было не в эту тему, разбираюсь.
-
Вроде в эту тему. Вопрос был здесь в #14
http://dl2kq.de/forum/index.php/topic,332.msg5016.html#msg5016
-
Ошибка была найдена. Была не пропаяна микросхема отраженки. Мост сбалансировался сразу после исправления, а после пропайки кабеля к экрану возле кольца - баланс сохранился до 30 мгц. Это примерно тоже самое что и вы показали только кольцо у меня в углу экрана из латуни село - экран на 60% вокруг трансформатора получился.