Skip to content

Instantly share code, notes, and snippets.

@AliBarber
Created January 2, 2021 16:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AliBarber/f5e125f240745ba4f1fa6f94ac022088 to your computer and use it in GitHub Desktop.
Save AliBarber/f5e125f240745ba4f1fa6f94ac022088 to your computer and use it in GitHub Desktop.
PWL of PWM Pulses
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#define RISE_FALL_TIME 1e-9
#define LOW 0.0
#define HIGH 3.3
#define MAX(a,b) ((a) > (b)) ? (a) : (b)
const unsigned int BITS_MAX_VAL[] = {0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536};
using namespace std;
double produce_pwl_single(const double period, const int resolution, const unsigned int value, double offset, ostream &out = cout){
// Writes a single 'pulse' to the output stream
// returns the end time of the pulse
double now = offset;
out << setprecision(10) << now << "\t" << setprecision(5) << LOW << endl;
if(value > 0){
double duration_of_on_pulse = ((double) value / BITS_MAX_VAL[resolution]) * period;
if(duration_of_on_pulse > (2 * RISE_FALL_TIME)){
now += RISE_FALL_TIME;
out << setprecision(10) << now << "\t" << setprecision(5) << HIGH << endl;
now += duration_of_on_pulse;
out << setprecision(10) << now << "\t" << setprecision(5) << HIGH << endl;
// LOW
now += RISE_FALL_TIME;
out << setprecision(10) << now << "\t" << setprecision(5) << LOW << endl;
}
}
return MAX(now, (offset + period));
}
float pwl_from_lut(fstream &in, const float frequency, const int resolution, const string file_path, const int update_period, ostream &out = cout){
string line;
float period_start_time = 0.f;
double period = 1.0 / frequency;
while(getline(in, line)){
// Don't use atoi here - actually catch and handle exceptions!
try{
const unsigned int value = static_cast<unsigned int>(stoi(line));
if(value < 0 || value > BITS_MAX_VAL[resolution]){
cerr << "Invalid value in LUT: " << line << endl;
return -1.f;
}
for(int i = 0; i < update_period; i++){
period_start_time = produce_pwl_single(period, resolution, value, period_start_time, out);
}
}
catch(const invalid_argument& arg_ex){
cerr << "Invalid value in LUT: " << line << endl;
return -1.f;
}
}
return period_start_time;
}
int main(int argc, char** argv){
// frequency, resolution (bits), value or LUT, update period
if(argc < 4){
cerr << "Usage:\n"
<< argv[0] << " FREQUENCY RESOLUTION VALUE/ LUT [UPDATE PERIOD]\n\n"
<< "FREQUENCY\t\t\t PWM Frequency in Hz\n"
<< "RESOLUTION\t\t\t PWM Resolution in bits\n"
<< "VALUE / LUT\t\t\t PWM Value (int) or path to a LUT of values\n"
<< "UPDATE PERIOD (Only for LUT)\t If using a LUT, number of PWM pulses before updating the value" << endl;
return 1;
}
const float pwm_freq = atof(argv[1]);
if(pwm_freq <= 0){
cerr << "Invalid value for frequency: " << argv[1] << endl;
return 1;
}
const int pwm_res = atoi(argv[2]);
if(pwm_res <= 0){
cerr << "Invalid value for resolution: " << argv[1] << endl;
return 1;
}
const string file_path_or_value(argv[3]);
try{
const unsigned int value = static_cast<unsigned int>(stoi(file_path_or_value));
double period = 1.0 / pwm_freq;
auto success = produce_pwl_single(period, pwm_res, 0.0, value);
if(success <= 0){
return 1;
}
return 0;
}
catch(const invalid_argument& arg_ex){
fstream file_in(file_path_or_value);
if(!file_in.is_open()){
cerr << "Could not open: " << file_path_or_value << endl;
return -1.f;
}
if(argc < 5){
cerr << "No update period supplied for use with LUT file" << endl;
return 1;
}
int update_period = atoi(argv[4]);
if(update_period <= 0){
cerr << "Invalid update period: " << argv[4] << endl;
return 1;
}
auto success = pwl_from_lut(file_in, pwm_freq, pwm_res, file_path_or_value, update_period);
if(success <= 0){
return 1;
}
return 0;
}
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment