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