Перейти к содержанию
    

Как состряпать алгоритм синусоидального ШИМ?

После преодоления этапа получения синуса через DDS возникла проблема с тем, какая часть этого синуса используется. Судя по коммутационным диаграммам (с замыканием нижних ключей в фазах на землю без ШИМ), используется только половина периода от 0 до 180гр. 

image.thumb.png.25494a63a2fd1dac0fa1690bb754bcb6.png

Вот картинка по сигналам на входах драйверов ключей

гибрид.png

нечётные - верхние ключи, чётные - нижние.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не смог пока придумать приемлемый вариант переключения ШИМ-синуса между верхними и нижними ключами. Реализовал на данный момент такой  вариант: отслеживаю значения синуса и при значении, совпадающим с нужной фазой, переключаюсь. Устраивает в этом методе то, что есть dead-time между выключением верхнего и включением нижнего ключа (и наоборот). Не устраивает то, что всё это делается в прерывании формирования ШИМ и длительность прерывания сильно увеличивается (но, как ни странно, ШИМ по-прежнему формируется нормально).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А просто анализировать значение фазы или тупо сделать второй массив с состояниями нижних ключей, из которого выбирать используя тот же самый фазовый аккумулятор? Или массив синуса заменить на массив структур, состоящих из значений синуса и состояния нижнего ключа? Или забить на младший бит синуса и вместо него хранить состояние нижнего ключа (у вас ведь по одному ключу на каждый выход синуса)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Сергей Борщ said:

А просто анализировать значение фазы

Так я это и делаю, только через значение синуса.

1 hour ago, Сергей Борщ said:

 сделать второй массив с состояниями нижних ключей, из которого выбирать используя тот же самый фазовый

А вот это отчего то не пришло в голову... Действительно просто. Спасибо за очередную подсказку!

 

1 hour ago, Сергей Борщ said:

Или забить на младший бит синуса и вместо него хранить состояние нижнего ключа (у вас ведь по одному ключу на каждый выход синуса)?

На каждую фазу по два ключа - к плюсу и к земле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, MPetrovich сказал:

На каждую фазу по два ключа - к плюсу и к земле.

Но на один из них подается ШИМ синуса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 minutes ago, Сергей Борщ said:

Но на один из них подается ШИМ синуса.

Да, в схеме управления, которую я пытаюсь реализовать, ШИМ подаётся только на верхние ключи фаз.

Я мысль вроде ухватил. Только вот мне кажется для схемы со сдвигом на 180гр. надо старший бит синуса использовать.  Тогда можно для нижнего ключа делать if(PWM1 & 0x80)LOW_KEY1 =1; 

Ну и для остальных фаз так же.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, хотел заметить, что кратное двум количество значений в таблице для ШИМ даёт неприятный побочный эффект - при прямом подсчёте и выводе на индикацию частоты синуса display = (((uint32_t)akk_shift) * 31250)/65536; набегает ошибка примерно в 2Гц на 50ГЦ. И происходит это похоже из-за "некруглости" таблицы.

То же самое, я думаю, будет наблюдаться и при переключении ключей по фазам. В обоих вариантах коммутации - при сдвиге на 180гр и на 120гр - надо иметь чёткое попадание в точки на синусе, соответствующие 30*N = (Пи/6)*N градусов .

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Надеюсь, вы оговорились и имели ввиду "кратное степени двойки количество значений таблицы".

8 часов назад, MPetrovich сказал:

набегает ошибка примерно в 2Гц на 50ГЦ. И происходит это похоже из-за "некруглости" таблицы.

Ошибка всегда "в минус"? тогда попробуйте display = ((((uint32_t)akk_shift) * 31250) + 65536 / 2)/65536;

Конечно, можно работать и с "некруглой" таблицей, тогда надо перед каждым увеличением аккумулятора фазы проверять, что он не выскочит за пределы таблицы, и если выскочит - отнимать 2*Пи. Или, что проще - не увеличивать, а уменьшать аккумулятор фазы и перед каждым уменьшением сравнивать его с шагом. Если он строго меньше шага - прибавлять 2*Пи. При удачном стечении обстоятельств компилятор может объединить сравнение и вычитание - сделать вычитание и при обнаружении заёма добавить 2*Пи

8 часов назад, MPetrovich сказал:

надо иметь чёткое попадание в точки на синусе, соответствующие 30*N = (Пи/6)*N градусов

На большой частоте эта точка таблицы может быть пропущена даже в очень большой таблице. Тут, думаю, скорее надо делать проверку if((akk_prev < table_size / 12) && (akk_cur >= table_size / 12)), т.е. если на этом шаге мы попадаем или перескакиваем искомую точку - то надо переключать. И делать аккумулятор фазы как можно большей разрядности для более точного отлова этого момента.

P.S. Все это - мои рассуждения с дивана, их можно принимать как толчок к осмысливанию, но ни в коем случае не как безусловное руководство к действию.

Из своего опыта могу посоветовать сделать таблицу на два периода синуса, чтобы три фазы получать методом akk + 0 * PERIOD / 3, akk + 1 * PERIOD / 3, akk + 2 * PERIOD / 3, при этом иметь "железный" сдвиг между фазами в 120 градусов и ни при каких akk в пределах [0...PERIOD) не вылететь за пределы таблицы, т.е. сэкономить проверку на выход за пределы таблицы для остальных двух фаз. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 minutes ago, Сергей Борщ said:

Ошибка всегда "в минус"?

Нет, "в плюс".

 

25 minutes ago, Сергей Борщ said:

На большой частоте эта точка таблицы может быть пропущена даже в очень большой таблице.

Каким образом N-е значение таблицы может быть пропущено? Аккумулятор же перебирает их подряд, а шаг всегда на пару-тройку порядков  меньше аккумулятора. Так что даже при большой частоте все значения таблицы будут по нескольку раз подряд выбраны в прерывании.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

50 минут назад, MPetrovich сказал:

а шаг всегда на пару-тройку порядков  меньше аккумулятора

Возможно, у вас это и так. У меня бывало иначе. Я стараюсь писать программы так, чтобы они работали при любых входных значениях 😉

Например, у меня был 8-битный phase and frequency correct PWM (510 тиков таймера на период ШИМ), тактовая  частота 16 МГц и таблица на 1020(510*2) точек на два периода (ну вот хотелось мне плавности, а памяти под такую таблицу даже в меге88 хватало). При генерации 400 Гц из 510 точек таблицы выбираются 78.43 (т.е. 78 точек, но в каждом периоде разные).

50 минут назад, MPetrovich сказал:

Нет, "в плюс".

Странно. У вас же вроде бы получалось около 0.47 Гц на единицу приращения аккумулятора фазы? Откуда же ошибка? Ну-ка показывайте, как вы частоту считаете. У меня получается с вашими исходными данными для 50 Гц akk_shift = 106, akk_shift * 31250 / 65536 = 50.5447387, т.е. при вычислении в целых должно получиться 50 ровно. Хотя я бы умножал на 312500 и последний знак результата отделял запятой. Показывать в целых герцах на таких частотах, мне кажется, грубовато. Заказчик будет морщить нос.

P.S. Да и "магическое число" 31250 тоже заставляет напрягаться. Вот честно-честно - лень думать, откуда оно взялось, приходится верить вам на слово. А вы через месяц сможете самому себе объяснить, откуда оно взялось? "Контрразведчик,должен знать всегда, как никто другой, что верить в наше время нельзя никому. Порой даже самому себе🤣

Я в таких случаях пишу полное выражение и пусть компилятор потрудится его вычислять. Зато у меня при просмотре этого кода всегда будет перед глазами исходная формула, пусть даже эта формула состоит из макросов. Вот, например, кусок кода трехфазного генератора:

    sinus::index_t Index = sinus::index(get_phase());
    Phase_out[PHASE_A] = uint16_t(sinus::value_by_index(Index + sinus::index(sinus::PERIOD * 0 / 3)) * Tmp) / 256;
    Phase_out[PHASE_B] = uint16_t(sinus::value_by_index(Index + sinus::index(sinus::PERIOD * 1 / 3)) * Tmp) / 256;
    Phase_out[PHASE_C] = uint16_t(sinus::value_by_index(Index + sinus::index(sinus::PERIOD * 2 / 3)) * Tmp) / 256;

Пусть у компилятора болит голова, чему именно равен период синуса "в морковках". Зато я четко вижу, что фазы сдвинуты на треть и две трети периода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 hours ago, Сергей Борщ said:

У вас же вроде бы получалось около 0.47 Гц на единицу приращения аккумулятора фазы?

Да, так и получается.

 

9 hours ago, Сергей Борщ said:

"магическое число" 31250 тоже заставляет напрягаться. Вот честно-честно - лень думать, откуда оно взялось, приходится верить вам на слово.

Fcpu=8Mhz; PWM = 8-bit; Fpwm=8000000/2^8=31250Hz. Никакой магии)

 

9 hours ago, Сергей Борщ said:

Ну-ка показывайте, как вы частоту считаете. У меня получается с вашими исходными данными для 50 Гц akk_shift = 106, akk_shift * 31250 / 65536 = 50.5447387, т.е. при вычислении в целых должно получиться 50 ровно.

Так и считаю. Но измеренный на осциллографе курсорами период даёт частоту на 2Гц больше при  akk_shift = 106.

Да бог с ней, с индикацией. Меня больше всего волнует сейчас вопрос как связать длину таблицы с выходной частотой. В формуле подсчёта частоты длина таблицы вообще не участвует, но на практике при таблице в 36 значений частота уменьшается в 1,67 раза. Откуда это берётся я не могу понять.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 минут назад, MPetrovich сказал:

Fpwm=8000000/2^8=31250Hz. Никакой магии)

https://ru.wikipedia.org/wiki/Магическое_число_(программирование)#Плохая_практика_программирования

48 минут назад, MPetrovich сказал:

Но измеренный на осциллографе курсорами период даёт частоту на 2Гц больше при  akk_shift = 106.

Ну это не показатель. У меня на работе agilent тоже частоту криво считает, даже при большом усреднении.

50 минут назад, MPetrovich сказал:

В формуле подсчёта частоты длина таблицы вообще не участвует,

Как не участвует? А 65536? Это как раз длина таблицы *2^N, где N - количество разрядов дробной части фазового аккумулятора.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Сергей Борщ said:

Так это в железе определено настройками таймера. Программирование здесь ни при чём. Или вместо 31250 Вы предлагаете определить:

  #define F_PWM   31250  ?

 

1 hour ago, Сергей Борщ said:

Ну это не показатель. У меня на работе agilent тоже частоту криво считает, даже при большом усреднении.

Я на осциллографе ПЕРИОД измеряю. Он поверенный, развёртка точная. Частоту я вижу на экране, но это результат 1/Т.

 

1 hour ago, Сергей Борщ said:

Как не участвует? А 65536? Это как раз длина таблицы *2^N, где N - количество разрядов дробной части фазового аккумулятора.

Длина таблицы 32 или 36. Я так понимаю, что чем длиннее таблица, тем меньше раз повторяется каждое значение при одинаковом шаге аккумулятора. По формуле подсчёта частоты выходит, что длина таблицы на частоту не влияет. Но так ли это я не уверен...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

42 minutes ago, MPetrovich said:

65536? Это как раз длина таблицы *2^N, где N - количество разрядов дробной части фазового аккумулятора.

Я тут подумал, может для таблицы в 36 значений вычислить другой размер фазового аккумулятора? Скажем такой: 36*1024=36864:russian_ru:

Да! Это работает! Только надо аккумулятор во такой сделать: 36*2048=73728 И длина таблицы тогда не влияет на частоту, при одинаковом шаге получается одинаковая частота.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет, не вариант. Искажается форма синуса на отрицательной полуволне.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...