import numpy as np
import pandas as pd
TARGET_F = 1 # In Hz so 50.0 is 0.020 seconds period and 0.25 is 4 seconds period
CLOCK_MCU = 240000000
TOLERANCE = 0.00000001
# -----------------------------------------------------
def abs_error(num1, num2):
return abs((num1
- num2
) / num1
)
def hertz
(clock, prescaler
, period
): f
= clock / (prescaler
* period
) return f
def perfect_divisors():
exacts = []
for psc in range(1, 65536):
arr = CLOCK_MCU / (TARGET_F * psc)
if CLOCK_MCU % psc == 0:
if arr <= 65536:
exacts.append(psc)
return exacts
def add_exact_period(prescaler):
entries = []
arr = CLOCK_MCU / (TARGET_F * prescaler)
if arr == int(arr):
entry = [prescaler, arr, TARGET_F, 0.0]
entries.append(entry)
return entries
def possible_prescaler_value():
possibles = []
for psc in range(1, 65536):
if psc in exact_prescalers:
continue
h1 = hertz(CLOCK_MCU, psc, 1)
h2 = hertz(CLOCK_MCU, psc, 65536)
if h1 >= TARGET_F >= h2:
possibles.append(psc)
return possibles
def close_divisor(psc, tolerance):
arr = CLOCK_MCU / (TARGET_F * psc)
error = abs_error(int(arr), arr)
if error < tolerance and arr < 65536.0:
h = hertz(CLOCK_MCU, psc, int(arr))
return psc, int(arr), h, error
else:
return None
# ------------------------------------------------------------------------
# Make a dataframe to hold results as we compute them
df = pd.DataFrame(columns=['PSC', 'ARR', 'F', 'ERROR'], dtype=np.double)
# Get exact prescalars first.
exact_prescalers = perfect_divisors()
exact_values = []
for index in range(len(exact_prescalers)):
rows = add_exact_period(exact_prescalers[index])
for rowindex in range(len(rows)):
df = df.append(pd.DataFrame(np.array(rows[rowindex]).reshape(1, 4), columns=df.columns))
# Get possible prescalers.
poss_prescalers = possible_prescaler_value()
close_prescalers = []
for index in range(len(poss_prescalers)):
value = close_divisor(poss_prescalers[index], TOLERANCE)
if value is not None:
close_prescalers.append((value[0], value[1], value[2], value[3]))
df = df.append(pd.DataFrame(np.array(close_prescalers).reshape(len(close_prescalers), 4), columns=df.columns))
# Adjust PSC and ARR values by -1 to reflect the way you'd code them.
df['PSC'] = df['PSC'] - 1
df['ARR'] = df['ARR'] - 1
# Sort first by errors (zeroes and lowest errors at top of list, and
# then by prescaler value (ascending).
df = df.sort_values(['ERROR', 'PSC'])
# Make and populate column indicating if combination is exact.
df['EXACT'] = pd.Series("?", index=df.index)
df['EXACT'] = np.where(df['ERROR'] == 0.0, "YES", "NO")
# Format for output.
df['PSC'] = df['PSC'].map('{:.0f}'.format)
df['ARR'] = df['ARR'].map('{:.0f}'.format)
df['F'] = df['F'].map('{:.6f}'.format)
df['ERROR'] = df['ERROR'].map('{:.10f}'.format)
output = df.to_string()
print(output)
print()
print('these are the ', df.shape[0], ' total combination meeting your tolerance requirement')
aW1wb3J0IG51bXB5IGFzIG5wCmltcG9ydCBwYW5kYXMgYXMgcGQKClRBUkdFVF9GID0gMSAgIyBJbiBIeiBzbyA1MC4wIGlzIDAuMDIwIHNlY29uZHMgcGVyaW9kIGFuZCAwLjI1IGlzIDQgc2Vjb25kcyBwZXJpb2QKQ0xPQ0tfTUNVID0gMjQwMDAwMDAwClRPTEVSQU5DRSA9IDAuMDAwMDAwMDEKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgpkZWYgYWJzX2Vycm9yKG51bTEsIG51bTIpOgogICAgcmV0dXJuIGFicygobnVtMSAtIG51bTIpIC8gbnVtMSkKCgpkZWYgaGVydHooY2xvY2ssIHByZXNjYWxlciwgcGVyaW9kKToKICAgIGYgPSBjbG9jayAvIChwcmVzY2FsZXIgKiBwZXJpb2QpCiAgICByZXR1cm4gZgoKCmRlZiBwZXJmZWN0X2Rpdmlzb3JzKCk6CiAgICBleGFjdHMgPSBbXQogICAgZm9yIHBzYyBpbiByYW5nZSgxLCA2NTUzNik6CiAgICAgICAgYXJyID0gQ0xPQ0tfTUNVIC8gKFRBUkdFVF9GICogcHNjKQogICAgICAgIGlmIENMT0NLX01DVSAlIHBzYyA9PSAwOgogICAgICAgICAgICBpZiBhcnIgPD0gNjU1MzY6CiAgICAgICAgICAgICAgICBleGFjdHMuYXBwZW5kKHBzYykKICAgIHJldHVybiBleGFjdHMKCgpkZWYgYWRkX2V4YWN0X3BlcmlvZChwcmVzY2FsZXIpOgogICAgZW50cmllcyA9IFtdCiAgICBhcnIgPSBDTE9DS19NQ1UgLyAoVEFSR0VUX0YgKiBwcmVzY2FsZXIpCiAgICBpZiBhcnIgPT0gaW50KGFycik6CiAgICAgICAgZW50cnkgPSBbcHJlc2NhbGVyLCBhcnIsIFRBUkdFVF9GLCAwLjBdCiAgICAgICAgZW50cmllcy5hcHBlbmQoZW50cnkpCiAgICByZXR1cm4gZW50cmllcwoKCmRlZiBwb3NzaWJsZV9wcmVzY2FsZXJfdmFsdWUoKToKICAgIHBvc3NpYmxlcyA9IFtdCiAgICBmb3IgcHNjIGluIHJhbmdlKDEsIDY1NTM2KToKICAgICAgICBpZiBwc2MgaW4gZXhhY3RfcHJlc2NhbGVyczoKICAgICAgICAgICAgY29udGludWUKICAgICAgICBoMSA9IGhlcnR6KENMT0NLX01DVSwgcHNjLCAxKQogICAgICAgIGgyID0gaGVydHooQ0xPQ0tfTUNVLCBwc2MsIDY1NTM2KQogICAgICAgIGlmIGgxID49IFRBUkdFVF9GID49IGgyOgogICAgICAgICAgICBwb3NzaWJsZXMuYXBwZW5kKHBzYykKICAgIHJldHVybiBwb3NzaWJsZXMKCgpkZWYgY2xvc2VfZGl2aXNvcihwc2MsIHRvbGVyYW5jZSk6CiAgICBhcnIgPSBDTE9DS19NQ1UgLyAoVEFSR0VUX0YgKiBwc2MpCiAgICBlcnJvciA9IGFic19lcnJvcihpbnQoYXJyKSwgYXJyKQogICAgaWYgZXJyb3IgPCB0b2xlcmFuY2UgYW5kIGFyciA8IDY1NTM2LjA6CiAgICAgICAgaCA9IGhlcnR6KENMT0NLX01DVSwgcHNjLCBpbnQoYXJyKSkKICAgICAgICByZXR1cm4gcHNjLCBpbnQoYXJyKSwgaCwgZXJyb3IKICAgIGVsc2U6CiAgICAgICAgcmV0dXJuIE5vbmUKCgojICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgTWFrZSBhIGRhdGFmcmFtZSB0byBob2xkIHJlc3VsdHMgYXMgd2UgY29tcHV0ZSB0aGVtCmRmID0gcGQuRGF0YUZyYW1lKGNvbHVtbnM9WydQU0MnLCAnQVJSJywgJ0YnLCAnRVJST1InXSwgZHR5cGU9bnAuZG91YmxlKQoKIyBHZXQgZXhhY3QgcHJlc2NhbGFycyBmaXJzdC4KZXhhY3RfcHJlc2NhbGVycyA9IHBlcmZlY3RfZGl2aXNvcnMoKQpleGFjdF92YWx1ZXMgPSBbXQpmb3IgaW5kZXggaW4gcmFuZ2UobGVuKGV4YWN0X3ByZXNjYWxlcnMpKToKICAgIHJvd3MgPSBhZGRfZXhhY3RfcGVyaW9kKGV4YWN0X3ByZXNjYWxlcnNbaW5kZXhdKQogICAgZm9yIHJvd2luZGV4IGluIHJhbmdlKGxlbihyb3dzKSk6CiAgICAgICAgZGYgPSBkZi5hcHBlbmQocGQuRGF0YUZyYW1lKG5wLmFycmF5KHJvd3Nbcm93aW5kZXhdKS5yZXNoYXBlKDEsIDQpLCBjb2x1bW5zPWRmLmNvbHVtbnMpKQoKIyBHZXQgcG9zc2libGUgcHJlc2NhbGVycy4KcG9zc19wcmVzY2FsZXJzID0gcG9zc2libGVfcHJlc2NhbGVyX3ZhbHVlKCkKY2xvc2VfcHJlc2NhbGVycyA9IFtdCmZvciBpbmRleCBpbiByYW5nZShsZW4ocG9zc19wcmVzY2FsZXJzKSk6CiAgICB2YWx1ZSA9IGNsb3NlX2Rpdmlzb3IocG9zc19wcmVzY2FsZXJzW2luZGV4XSwgVE9MRVJBTkNFKQogICAgaWYgdmFsdWUgaXMgbm90IE5vbmU6CiAgICAgICAgY2xvc2VfcHJlc2NhbGVycy5hcHBlbmQoKHZhbHVlWzBdLCB2YWx1ZVsxXSwgdmFsdWVbMl0sIHZhbHVlWzNdKSkKZGYgPSBkZi5hcHBlbmQocGQuRGF0YUZyYW1lKG5wLmFycmF5KGNsb3NlX3ByZXNjYWxlcnMpLnJlc2hhcGUobGVuKGNsb3NlX3ByZXNjYWxlcnMpLCA0KSwgY29sdW1ucz1kZi5jb2x1bW5zKSkKCiMgIEFkanVzdCBQU0MgYW5kIEFSUiB2YWx1ZXMgYnkgLTEgdG8gcmVmbGVjdCB0aGUgd2F5IHlvdSdkIGNvZGUgdGhlbS4KZGZbJ1BTQyddID0gZGZbJ1BTQyddIC0gMQpkZlsnQVJSJ10gPSBkZlsnQVJSJ10gLSAxCgojICBTb3J0IGZpcnN0IGJ5IGVycm9ycyAoemVyb2VzIGFuZCBsb3dlc3QgZXJyb3JzIGF0IHRvcCBvZiBsaXN0LCBhbmQKIyAgdGhlbiBieSBwcmVzY2FsZXIgdmFsdWUgKGFzY2VuZGluZykuCmRmID0gZGYuc29ydF92YWx1ZXMoWydFUlJPUicsICdQU0MnXSkKCiMgTWFrZSBhbmQgcG9wdWxhdGUgY29sdW1uIGluZGljYXRpbmcgaWYgY29tYmluYXRpb24gaXMgZXhhY3QuCmRmWydFWEFDVCddID0gcGQuU2VyaWVzKCI/IiwgaW5kZXg9ZGYuaW5kZXgpCmRmWydFWEFDVCddID0gbnAud2hlcmUoZGZbJ0VSUk9SJ10gPT0gMC4wLCAiWUVTIiwgIk5PIikKCiMgIEZvcm1hdCBmb3Igb3V0cHV0LgpkZlsnUFNDJ10gPSBkZlsnUFNDJ10ubWFwKCd7Oi4wZn0nLmZvcm1hdCkKZGZbJ0FSUiddID0gZGZbJ0FSUiddLm1hcCgnezouMGZ9Jy5mb3JtYXQpCmRmWydGJ10gPSBkZlsnRiddLm1hcCgnezouNmZ9Jy5mb3JtYXQpCmRmWydFUlJPUiddID0gZGZbJ0VSUk9SJ10ubWFwKCd7Oi4xMGZ9Jy5mb3JtYXQpCgpvdXRwdXQgPSBkZi50b19zdHJpbmcoKQpwcmludChvdXRwdXQpCnByaW50KCkKcHJpbnQoJ3RoZXNlIGFyZSB0aGUgJywgZGYuc2hhcGVbMF0sICcgdG90YWwgY29tYmluYXRpb24gbWVldGluZyB5b3VyIHRvbGVyYW5jZSByZXF1aXJlbWVudCcpCmV4aXQoMCk=