Created
January 2, 2021 16:44
-
-
Save AliBarber/f5e125f240745ba4f1fa6f94ac022088 to your computer and use it in GitHub Desktop.
PWL of PWM Pulses
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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