<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
Step1:  1ère partie 
Step2:  Il nous faut construire le vecteur des $\Delta T _ i$ à partir des mesures de fréquences. On construit d'abord le vecteur des $F_i$
Step3:  note importante 
Step4:  attention les tensions sont bien en Newton, pas en kg comme dans la feuille Numbers.
Construction de la matrice à inverser pour obtenir les raideurs du modèle
On peut maintenant construire une première matrice de 5 lignes fois 6 colonnes.
Step5:  On s'attend à ce qu'il n'y ait qu'une valeur qui a augmenté, ici c'est la première.
Step7:  On peut écrire une fonction avec le code précédent 
Step8:  On vérifie que le RHS est correct 
Step9:  On peut maintenant construire les deux matrices 
Step10:  On peut les concaténer 
Step11:  Inversion du système ainsi construit
On peut maintenant inverser le système 
Step12:  On a la solution ! 
cependant on note que les raideurs ne sont pas exactement dans l'ordre croissant !! Problème ou pas ?
Vérification des prédictions du modèle
On peut maintenant voir si ces coefs permettent de bien prédire la variation de tension observée. On peut tout simplement repartir des matrices mat1 et mat2 et vérifier que l'on tombe bien sur ce qu'on veut.
Step13:  Mouai...
Step14:  Ceci est peut être dû à l'erreur à l'issue de la régression linéaire... on va quand même essayer d'implémenter la méthode d'inversion pour l'accordage.
ou au mauvais $\mu_i$, qui ont été choisis... au hasard ?
Construction de la matrice nécessaire à la méthode d'accordage
Il faut ici encore construire la matrice responsable de l'accordage.
Step15:  On vérifie que ces termes sont les bons.
Step16:  On écrit la fonction pour calculer la matrice 
Step17:  On peut maintenant inverser la matrice en calculant l'accordage cible.
Step18:  Le $\Delta f$ à appliquer peut se calculer en faisant la différence à obtenir 
Step19:  L'écart que l'on cherche à obtenir est donc 
Step20:  On doit le mettre au carré 
Step21:  On doit prendre la racine de ce grand F pour trouver les fréquences à appliquer 
Step22:  Cela devrait marcher. Voyons voir quels deltas de fréquence il faut imposer.
Step23:  Essai pratique
Testons !
Step24:  Conclusion 
Step25:  J'ai remesuré la longueur des cordes et j'ai trouvé 65 cm. Je décide de garder la longueur standard de 0.648 m.
On en déduit les Psi_i 
Step27:  On peut maintenant remesurer les différentes fréquences sur la guitare 
Step28:  Cette fois-ci on constate que les rho_i sont dans l'ordre !
Step29:  Bizarre la vérification...
Step30:  3ème partie 
Step31:  Afin de faire les prochaines mesures, on écrit la partie restante de l'application avec PyQt.
On désaccorde successivement le mi grave et le la pour obtenir les relevés suivants (à 0.1 Hz) 
Step32:  On peut regarder la somme des tensions (et la remettre en kg pour avoir une petite idée) 
Step33:  On constate qu'on reste proche, mais qu'on ne conserve pas exactement les tensions. Je me demande ce que prédit le modèle à ce sujet.
Step34:  Cette fois-ci, la prédiction n'est pas si mauvaise...
Prédictions successives du modèle
On peut maintenant calculer la matrice d'accord (dans le cadre du modèle linéaire).
Step36:  Et maintenant, on peut prédire les changements à partir d'un état vers un autre 
Step37:  attention au calcul des target_dF, c'est 
Step38:  On peut maintenant écrire la séquence attendue 
Step40:  On peut écrire une fonction qui facilite le calcul 
Step41:  Etape 0 
Step42:  Les fréquences cibles des cordes sont 
Step43:  Etape 1 
Step44:  La
Step45:  Ré
Step46:  Sol
Step47:  Si
Step48:  Mi aigu
Step49:  J'ai envie de penser que cela suffit.
à faire demain 
Step50:  On peut remarquer que l'inversion ne donne pas des valeurs satisfaisantes car les signes du produit matrice vecteur ne respectent pas celles observées (que des moins ou que des plus). On peut imaginer faire plus de mesures pour voir ce que ça donne 
Step51:  On laisse tomber et on recommence la procédure de calibration, avec un précision supérieure 
Step52:  Tout est de même signe, c'est pas si mal. Et l'erreur est faible.
Accordage
Step53:  Mi grave 
Step54:  La 
Step55:  Re 
Step56:  Sol 
Step57:  Si 
Step58:  Mi 
<ASSISTANT_TASK:>
Python Code:
data = 79,05	102,40	115,40	126,10	217,50	240,70
82,4	101,5	114,1	123,1	215,8	239
81,90	104,80	113,20	121,50	214,20	237,50
data = data.replace(',', '.')
lines = data.split('\n')
values = [line.split('\t') for line in lines]
values
import numpy as np
import pandas as pd
s = pd.DataFrame(values)
s
s.values.astype(np.float)
df = pd.DataFrame(s.values.astype(np.float), columns=range(6))
df
Explanation: 1ère partie : anciennes cordes, $\mu_i$ mal choisis
Importation des données après deux désaccordages
On va tout d'abord importer les données mesurées pour en déduire les $\rho_i$.
End of explanation
df ** 2
(df ** 2).ix[0][0]
Explanation: Il nous faut construire le vecteur des $\Delta T _ i$ à partir des mesures de fréquences. On construit d'abord le vecteur des $F_i$
End of explanation
freqs = np.array([82.4, 110., 146.8, 196., 246.9, 329.6]) # frequencies of the guitar strings, from low E to high E, in Hz
calibration_tensions = np.array([9.59, 11.61, 11.22, 8.43, 8.09, 8.9]) * 9.81 # calibration tensions found on package (in kg) converted to N
mu = calibration_tensions / (4 * 0.648**2 * freqs**2) 
mu
psi = 4 * 0.648**2 * mu
psi
T = (df ** 2).values * psi
T
Explanation: note importante : j'utilise ici des $mu_i$ qui sont lus sur une pochette de cordes. Je n'ai aucune garantie que cela soient bien les vrais $mu_i$ nécessaires aux cordes qui sont sur ma guitare !
End of explanation
T_end = T[1, :]
T_start = T[0, :]
mat = np.zeros((5, 6))
dT = T_end - T_start
dT
mat
Explanation: attention les tensions sont bien en Newton, pas en kg comme dans la feuille Numbers.
Construction de la matrice à inverser pour obtenir les raideurs du modèle
On peut maintenant construire une première matrice de 5 lignes fois 6 colonnes.
End of explanation
np.nonzero(dT > 0)
tuned_string = np.nonzero(dT > 0)[0]
assert tuned_string.size == 1
tuned_string = tuned_string[0]
tuned_string
cnt = 0
for string in range(6):
        if string == tuned_string:
            continue
        else:
            for other_string in range(6):
                if other_string == tuned_string:
                    mat[cnt, other_string] = 0
                elif other_string == string:
                    mat[cnt, other_string] = dT[tuned_string] + dT[string]
                else:
                    mat[cnt, other_string] = dT[string]
            cnt += 1
mat[0]
mat[1]
mat
Explanation: On s'attend à ce qu'il n'y ait qu'une valeur qui a augmenté, ici c'est la première.
End of explanation
def make_matrix(T_end, T_start):
     builds the matrix that describes the effect of the individual rho_i on the 
    overall tuning change
    M * [rho_i] = [dT]
    
    mat = np.zeros((5, 6))
    dT = T_end - T_start
    upstrings = np.nonzero(dT > 0)[0]
    downstrings = np.nonzero(dT < 0)[0]
    if (upstrings.size == 5) and (downstrings.size == 1):
        tuned_string = downstrings[0]
    elif (upstrings.size == 1) and (downstrings.size == 5):
        tuned_string = upstrings[0]
    else:
        raise Exception('problem: no changed string was detected!')
    cnt = 0
    for string in range(6):
            if string == tuned_string:
                continue
            else:
                for other_string in range(6):
                    if other_string == tuned_string:
                        mat[cnt, other_string] = 0
                    elif other_string == string:
                        mat[cnt, other_string] = dT[tuned_string] + dT[string]
                    else:
                        mat[cnt, other_string] = dT[string]
                cnt += 1
    rhs = -dT[[_ for _ in range(6) if _ != tuned_string]] 
    return mat, rhs
make_matrix(T_end, T_start)
Explanation: On peut écrire une fonction avec le code précédent :
End of explanation
dT
Explanation: On vérifie que le RHS est correct :
End of explanation
mat1, rhs1 = make_matrix(T[1, :], T[0, :])
mat2, rhs2 = make_matrix(T[2, :], T[1, :])
mat2
rhs2
Explanation: On peut maintenant construire les deux matrices :
End of explanation
total_mat = np.vstack((mat1, mat2))
total_rhs = np.vstack((rhs1[:, np.newaxis], 
                       rhs2[:, np.newaxis]))
total_mat
total_rhs
Explanation: On peut les concaténer :
End of explanation
total_mat.shape
total_rhs.shape
rho, err, rank, eigs = np.linalg.lstsq(total_mat, total_rhs)
err
rho
err
Explanation: Inversion du système ainsi construit
On peut maintenant inverser le système :
End of explanation
np.dot(mat1, rho)
rhs1
Explanation: On a la solution ! 
cependant on note que les raideurs ne sont pas exactement dans l'ordre croissant !! Problème ou pas ?
Vérification des prédictions du modèle
On peut maintenant voir si ces coefs permettent de bien prédire la variation de tension observée. On peut tout simplement repartir des matrices mat1 et mat2 et vérifier que l'on tombe bien sur ce qu'on veut.
End of explanation
np.dot(mat2, rho)
rhs2
Explanation: Mouai...
End of explanation
tuning_mat = np.zeros((6, 6))
for other_string in range(6):
    for tuning_string in range(6):
        if tuning_string == other_string:
            tuning_mat[other_string, tuning_string] = 1.
        else:
            tuning_mat[other_string, tuning_string] = \
                    psi[tuning_string] / psi[other_string] * \
                        (- rho[other_string] / (1 + np.sum([rho[i] for i in range(6) if i != tuning_string])))
tuning_mat
np.dot(tuning_mat, np.array([1, 0, 0, 0, 0, 0]))
Explanation: Ceci est peut être dû à l'erreur à l'issue de la régression linéaire... on va quand même essayer d'implémenter la méthode d'inversion pour l'accordage.
ou au mauvais $\mu_i$, qui ont été choisis... au hasard ?
Construction de la matrice nécessaire à la méthode d'accordage
Il faut ici encore construire la matrice responsable de l'accordage.
End of explanation
psi[0] / psi[1] * (- rho[1] / (1 + np.sum([rho[k] for k in range(6) if k != 0])))
Explanation: On vérifie que ces termes sont les bons.
End of explanation
def compute_tuning_matrix(psi, rho):
    tuning_mat = np.zeros((6, 6))
    for other_string in range(6):
        for tuning_string in range(6):
            if tuning_string == other_string:
                tuning_mat[other_string, tuning_string] = 1.
            else:
                tuning_mat[other_string, tuning_string] = \
                        psi[tuning_string] / psi[other_string] * \
                            (- rho[other_string] / (1 + np.sum([rho[i] for i in range(6) if i != tuning_string])))
    return tuning_mat
compute_tuning_matrix(psi, rho)
Explanation: On écrit la fonction pour calculer la matrice :
End of explanation
freqs
Explanation: On peut maintenant inverser la matrice en calculant l'accordage cible.
End of explanation
target_freqs = freqs.copy()
current_freqs = df.values[2, :]
Explanation: Le $\Delta f$ à appliquer peut se calculer en faisant la différence à obtenir :
End of explanation
target_freqs - current_freqs
Explanation: L'écart que l'on cherche à obtenir est donc :
End of explanation
target_dF = (target_freqs - current_freqs) ** 2
Delta_F = np.linalg.solve(tuning_mat, target_dF)
Delta_F
Explanation: On doit le mettre au carré :
End of explanation
np.sqrt(Delta_F)
np.sqrt(np.dot(tuning_mat, Delta_F))
current_freqs
current_freqs + np.sqrt(np.dot(tuning_mat, Delta_F))
Explanation: On doit prendre la racine de ce grand F pour trouver les fréquences à appliquer :
End of explanation
np.sqrt(Delta_F)
Explanation: Cela devrait marcher. Voyons voir quels deltas de fréquence il faut imposer.
End of explanation
current_freqs + np.sqrt(Delta_F)
Explanation: Essai pratique
Testons !
End of explanation
freqs = np.array([82.4, 110., 146.8, 196., 246.9, 329.6]) # frequencies of the guitar strings, from low E to high E, in Hz
calibration_tensions = np.array([7.94, 8.84, 8.34, 6.67, 4.99, 5.94]) * 9.81 # calibration tensions found on package (in kg) converted to N
mu = calibration_tensions / (4 * 0.648**2 * freqs**2) 
mu
Explanation: Conclusion : ça n'a pas marché et le pont n'a pas arrêté de monter. Je pense que cela vient d'autre chose : la tension du set de cordes n'était pas adaptée !!! 
Je change donc de set de cordes et je recommence.
2ème partie : nouvelles cordes, avec propriétés connues
J'ai mis des nouvelles cordes dont les propriétés sont les suivantes :
mi aigu .009 5.94 kg
si .011 4.99 kg
sol .016 6.67 kg
ré .026 8.34 kg
la .036 8.84 kg
mi grave .046 7.94 kg
On en déduit les $\mu_i$ :
End of explanation
psi = 4 * 0.648**2 * mu
psi
Explanation: J'ai remesuré la longueur des cordes et j'ai trouvé 65 cm. Je décide de garder la longueur standard de 0.648 m.
On en déduit les Psi_i :
End of explanation
lines = 83,55	94,70	193,7	138,8	203	190
89,2	93,3	192,55	135,2	200,55	186,9
87,8	99,2	191,25	130,9	197,85	183,7.replace(',', '.').split('\n')
history = np.array([line.split('\t') for line in lines], dtype=np.float)
history
T = (history ** 2) * psi
mat1, rhs1 = make_matrix(T[1, :], T[0, :])
mat2, rhs2 = make_matrix(T[2, :], T[1, :])
total_mat = np.vstack((mat1, mat2))
total_rhs = np.vstack((rhs1[:, np.newaxis], 
                       rhs2[:, np.newaxis]))
rho, err, rank, eigs = np.linalg.lstsq(total_mat, total_rhs)
rho
err
Explanation: On peut maintenant remesurer les différentes fréquences sur la guitare :
End of explanation
np.dot(mat1, rho)
rhs1
np.dot(mat2, rho)
rhs2
np.dot(total_mat, rho)
total_rhs
Explanation: Cette fois-ci on constate que les rho_i sont dans l'ordre !
End of explanation
tuning_mat = compute_tuning_matrix(psi, rho)
tuning_mat
target_freqs = freqs.copy()
current_freqs = history[2, :]
target_freqs - current_freqs
target_dF = (target_freqs - current_freqs) ** 2
Delta_F = np.linalg.solve(tuning_mat, target_dF)
Delta_F
np.sqrt(Delta_F)
for _ in np.sqrt(Delta_F):
    print("{:.2f}".format(_))
Explanation: Bizarre la vérification...
End of explanation
freqs = np.array([82.4, 110., 146.8, 196., 246.9, 329.6]) # frequencies of the guitar strings, from low E to high E, in Hz
calibration_tensions = np.array([7.94, 8.84, 8.34, 6.67, 4.99, 5.94]) * 9.81 # calibration tensions found on package (in kg) converted to N
mu = calibration_tensions / (4 * 0.648**2 * freqs**2) 
psi = 4 * 0.648**2 * mu
Explanation: 3ème partie : travail sur la méthode d'accordage
Un des problèmes des parties précédentes provient du fait que l'accordage modifie au fur et à mesure les tensions des cordes et que lorsqu'on veut accorder la deuxième corde, on se pose la question de sa tension cible, qui a déjà changé par rapport aux conditions initiales.
Il y a deux possibilités :
calculer la tension d'arrivée à l'issue de l'accordage de la première corde prédite par le modèle pour toutes les cordes et l'utiliser pour calculer la tension cible de la deuxième corde
remesurer toutes les tensions des cordes et ajouter l'incrément de tension nécessaire à la deuxième corde selon ce qui a été calculé par le modèle
Idéalement, c'est à dire si le modèle est correct et que les paramètres ont été bien estimés, les deux méthodes se rejoignent.
Dans cette partie, nous allons confronter dans un premier temps les variations mesurées à l'issue d'un désaccordage avec les variations prédites. Dans un deuxième temps, nous conclurons sur la méthode à utiliser parmi les deux possibilités évoquées ci-dessus.
Validation précise du modèle
Plan de cette partie : 
ré-inverser le modèle avec des nouvelles mesures indépendantes de la première série ci-dessus ; comparer les rho_i obtenus (on s'attend à trouver à peu près la même chose !)
faire les étapes d'accordage une par une et comparer à chaque étape la fréquence mesurée sur la guitare pour chaque corde ainsi que celle prédite par la méthode
Inversion du modèle
Propriétés de la guitare connues à l'avance :
End of explanation
history = np.array([[84.6,111.4,148.8,193.8,244.3,328.7],
[82.1,111.6,149.0,194.1,244.5,329.0],
[81.8,114.6,148.8,193.7,244.2,328.7]]) 
history
T = (history ** 2) * psi
T
Explanation: Afin de faire les prochaines mesures, on écrit la partie restante de l'application avec PyQt.
On désaccorde successivement le mi grave et le la pour obtenir les relevés suivants (à 0.1 Hz) :
End of explanation
T.sum(axis=1) / 9.81
Explanation: On peut regarder la somme des tensions (et la remettre en kg pour avoir une petite idée) :
End of explanation
mat1, rhs1 = make_matrix(T[1, :], T[0, :])
mat2, rhs2 = make_matrix(T[2, :], T[1, :])
total_mat = np.vstack((mat1, mat2))
total_rhs = np.vstack((rhs1[:, np.newaxis], 
                       rhs2[:, np.newaxis]))
rho, err, rank, eigs = np.linalg.lstsq(total_mat, total_rhs)
rho
err
np.dot(total_mat, rho)
total_rhs
Explanation: On constate qu'on reste proche, mais qu'on ne conserve pas exactement les tensions. Je me demande ce que prédit le modèle à ce sujet.
End of explanation
tuning_mat = compute_tuning_matrix(psi, rho)
tuning_mat
Explanation: Cette fois-ci, la prédiction n'est pas si mauvaise...
Prédictions successives du modèle
On peut maintenant calculer la matrice d'accord (dans le cadre du modèle linéaire).
End of explanation
def predict_changes(initial_T, final_T, tuning_mat):
    predicts changes in tuning (frequency) from a vector of tensions
    print("initial tunings: {:.2f}, {:.2f}, {:.2f}, {:.2f}, {:.2f}, {:.2f}".format(*[x for x in np.sqrt(initial_T))]))
    print("final tunings: {:.2f}, {:.2f}, {:.2f}, {:.2f}, {:.2f}, {:.2f}".format(*[x for x in np.sqrt(final_T))]))
    print("predicted tunings")
Explanation: Et maintenant, on peut prédire les changements à partir d'un état vers un autre :
End of explanation
target_freqs = freqs.copy()
current_freqs = history[2, :]
target_dF = target_freqs**2 - current_freqs**2
Delta_F = np.linalg.solve(tuning_mat, target_dF)
Delta_F
np.sqrt(current_freqs**2 + np.dot(tuning_mat, Delta_F))
target_freqs
Explanation: attention au calcul des target_dF, c'est :
$$
\delta F = f_{target}^2 - f_{current}^2
$$
End of explanation
print("initial: {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}".format(*[x for x in current_freqs]))
for step in range(6):
    new_F = np.sqrt(current_freqs**2 + np.dot(tuning_mat, Delta_F * (np.arange(6) <= step)))
    print(" step {}: {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}".format(step, *[x for x in new_F]))
    
Explanation: On peut maintenant écrire la séquence attendue :
End of explanation
def tuning_step(tuning_mat, initial_freqs, Delta_F, step_number):
    predicts observed tuning as a function of tuning step
    convention: step 0 means nothing has changed
    step = step_number - 1
    if step == -1:
        return initial_freqs
    return np.sqrt(initial_freqs**2 + np.dot(tuning_mat, Delta_F * (np.arange(6) <= step)))
print_strings = lambda v: print("{:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}, {:.1f}".format(*v))
Explanation: On peut écrire une fonction qui facilite le calcul :
End of explanation
%matplotlib inline
import matplotlib.pyplot as plt
initial_freqs = current_freqs.copy()
Explanation: Etape 0 : le programme
End of explanation
for target, string in zip([tuning_step(tuning_mat, initial_freqs, Delta_F, i)[i-1] for i in range(1, 7)],
                          ["low E", "A", "D", "G", "B", "high E"]):
    print("string: {}, target frequency: {:.1f}".format(string, target))
Explanation: Les fréquences cibles des cordes sont :
End of explanation
measured_freqs = [82.0,114.5,148.5,193.5,244.0,328.7]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 1)
print_strings(measured_freqs)
print_strings(expected_freqs)
plt.plot(measured_freqs, 'o')
plt.plot(expected_freqs, 'o')
Explanation: Etape 1 : mi grave
End of explanation
measured_freqs = [82.3,110.0,148.8,194.1,244.5,329.2]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 2)
print_strings(measured_freqs)
print_strings(expected_freqs)
plt.plot(measured_freqs, 'o')
plt.plot(expected_freqs, 'o')
Explanation: La
End of explanation
measured_freqs = [82.4,110.2,146.9,194.4,244.7,329.5]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 3)
print_strings(measured_freqs)
print_strings(expected_freqs)
plt.plot(measured_freqs, 'o')
plt.plot(expected_freqs, 'o')
Explanation: Ré
End of explanation
measured_freqs = [82.4,110.2,147.0,196.1,244.6,329.2]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 4)
print_strings(measured_freqs)
print_strings(expected_freqs)
plt.plot(measured_freqs, 'o')
plt.plot(expected_freqs, 'o')
Explanation: Sol
End of explanation
measured_freqs = [82.4,110.2,146.9,196.3,246.8,329.2]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 5)
print_strings(measured_freqs)
print_strings(expected_freqs)
plt.plot(measured_freqs, 'o')
plt.plot(expected_freqs, 'o')
Explanation: Si
End of explanation
measured_freqs = [82.4,110.1,146.9,196.3,246.7,329.6]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 6)
print_strings(measured_freqs)
print_strings(expected_freqs)
plt.plot(measured_freqs, 'o')
plt.plot(expected_freqs, 'o')
Explanation: Mi aigu
End of explanation
freqs = np.array([82.4, 110., 146.8, 196., 246.9, 329.6]) # frequencies of the guitar strings, from low E to high E, in Hz
calibration_tensions = np.array([7.94, 8.84, 8.34, 6.67, 4.99, 5.94]) * 9.81 # calibration tensions found on package (in kg) converted to N
mu = calibration_tensions / (4 * 0.648**2 * freqs**2) 
psi = 4 * 0.648**2 * mu
history = np.array([[83.7,112.7,151.3,204.2,251.2,333.4],
                    [84.9,112.3,150.9,203.3,250.5,332.8],
                    [85.0,109.4,151.1,203.9,250.9,333.0]]) 
history
T = (history ** 2) * psi
T.sum(axis=1) / 9.81
mat1, rhs1 = make_matrix(T[1, :], T[0, :])
mat2, rhs2 = make_matrix(T[2, :], T[1, :])
total_mat = np.vstack((mat1, mat2))
total_rhs = np.vstack((rhs1[:, np.newaxis], 
                       rhs2[:, np.newaxis]))
rho, err, rank, eigs = np.linalg.lstsq(total_mat, total_rhs)
rho
err
np.dot(total_mat, rho)
total_rhs
Explanation: J'ai envie de penser que cela suffit.
à faire demain :
refaire une inversion
refaire un accordage en quantifiant l'erreur en demi-tons par rapport à la note cible
20150811
Effet du serrage des boulons en tête de guitare sur l'accordage :
avant : 83.3,112.8,150.0,201.3,250.2,334.3
après : 83.1,112.9,149.7,201.3,250.4,334.5
Conclusion : petit effet, on va négliger ça.
J'utilise le protocole d'accordage suivant (attention différent de celui de l'étape précédente où j'avais descendu le mi et monté le la) :
je monte le mi grave
je descend le la
Au préalable, je met toutes les vis dans leurs positions neutres sur le vibrato pour le fine tuning.
Inversion
End of explanation
history = np.vstack((history,
                     np.array([82.3,109.5,151.3,204.0,251.1,333.3])))
history
T = (history ** 2) * psi
mat3, rhs3 = make_matrix(T[3, :], T[2, :])
total_mat = np.vstack((mat1, mat2, mat3))
total_rhs = np.vstack((rhs1[:, np.newaxis], 
                       rhs2[:, np.newaxis],
                       rhs3[:, np.newaxis]))
rho, err, rank, eigs = np.linalg.lstsq(total_mat, total_rhs)
rho
err
np.dot(total_mat, rho)
total_rhs
Explanation: On peut remarquer que l'inversion ne donne pas des valeurs satisfaisantes car les signes du produit matrice vecteur ne respectent pas celles observées (que des moins ou que des plus). On peut imaginer faire plus de mesures pour voir ce que ça donne : je vais rajouter un désaccordage.
End of explanation
history = np.array([[81.08,110.53,151.17,203.89,251.09,333.24],
                    [82.9,110.47,151.04,203.57,250.96,333.19],
                    [82.87,112.37,150.96,203.42,250.69,333.02]]) 
history
T = (history ** 2) * psi
T.sum(axis=1) / 9.81
mat1, rhs1 = make_matrix(T[1, :], T[0, :])
mat2, rhs2 = make_matrix(T[2, :], T[1, :])
total_mat = np.vstack((mat1, mat2))
total_rhs = np.vstack((rhs1[:, np.newaxis], 
                       rhs2[:, np.newaxis]))
rho, err, rank, eigs = np.linalg.lstsq(total_mat, total_rhs)
rho
err
np.dot(total_mat, rho)
total_rhs
Explanation: On laisse tomber et on recommence la procédure de calibration, avec un précision supérieure :
End of explanation
tuning_mat = compute_tuning_matrix(psi, rho)
target_freqs = freqs.copy()
current_freqs = history[2, :]
target_dF = target_freqs**2 - current_freqs**2
Delta_F = np.linalg.solve(tuning_mat, target_dF)
Delta_F
initial_freqs = current_freqs.copy()
initial_freqs
for target, string in zip([tuning_step(tuning_mat, initial_freqs, Delta_F, i)[i-1] for i in range(1, 7)],
                          ["low E", "A", "D", "G", "B", "high E"]):
    print("string: {}, target frequency: {:.1f}".format(string, target))
Explanation: Tout est de même signe, c'est pas si mal. Et l'erreur est faible.
Accordage
End of explanation
measured_freqs = [82.18,112.37,150.94,203.43,250.67,333.08]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 1)
print_strings(measured_freqs)
print_strings(expected_freqs)
Explanation: Mi grave :
End of explanation
measured_freqs = [82.44,109.75,150.91,203.92,251.13,333.26]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 2)
print_strings(measured_freqs)
print_strings(expected_freqs)
Explanation: La :
End of explanation
measured_freqs = [82.66,110.12,146.65,204.46,251.57,333.51]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 3)
print_strings(measured_freqs)
print_strings(expected_freqs)
Explanation: Re :
End of explanation
measured_freqs = [82.86,110.39,146.96,195.81,251.94,333.99]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 4)
print_strings(measured_freqs)
print_strings(expected_freqs)
Explanation: Sol :
End of explanation
measured_freqs = [82.97,110.52,147.1,196.29,246.53,334.24]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 5)
print_strings(measured_freqs)
print_strings(expected_freqs)
Explanation: Si :
End of explanation
measured_freqs = [83.2,110.75,147.17,196.55,246.67,329.84]
expected_freqs = tuning_step(tuning_mat, initial_freqs, Delta_F, 6)
print_strings(measured_freqs)
print_strings(expected_freqs)
Explanation: Mi :
End of explanation
<END_TASK>